library(tidyverse)
library(cowplot)
library(gggenes)
library(nlme)
Attaching package: ‘nlme’
The following object is masked from ‘package:dplyr’:
collapse
library(randomForest)
randomForest 4.6-14
Type rfNews() to see new features/changes/bug fixes.
Attaching package: ‘randomForest’
The following object is masked from ‘package:dplyr’:
combine
The following object is masked from ‘package:ggplot2’:
margin
library(pROC)
Type 'citation("pROC")' for a citation.
Attaching package: ‘pROC’
The following objects are masked from ‘package:stats’:
cov, smooth, var
library(glmnet)
Loading required package: Matrix
Attaching package: ‘Matrix’
The following objects are masked from ‘package:tidyr’:
expand, pack, unpack
Loaded glmnet 4.1-3
#Rejoin split files containing variant info
system2("cat", args = "./variant_lists/all_changes*", stdout = "all_consensus_minority_changes.csv")
system2("cat", args = "./variant_lists/minor_changes*", stdout = "variant_sites_all.csv")
system2("cat", args = "./variant_lists/replicates*", stdout = "replicated_samples.csv")
Information about sample collection, quality, and sequencing run
Connecting samples and metadata
#samples received from Houston, processed through timo pipeline and assigned Pango lineage
all_samples_timo_processed<-read.csv("full_lineage_report.tsv")
mcov_samples <- all_samples_timo_processed %>% filter(startsWith(taxon, "MCoV")) %>% mutate(MCoVNumber=regmatches(taxon, regexpr("MCoV.[0-9]+", taxon)) %>% str_remove("-") %>% str_remove("_")) %>% select(MCoVNumber, pango_lineage=lineage)
#a few samples don't have names formatted MCoV###, resulting in identical MCoV ids. Filter these out rather than renaming manually
duplicated_mcov_numbers <- mcov_samples %>% filter(duplicated(MCoVNumber)==TRUE) %>% pull(MCoVNumber)
mcov_samples <- mcov_samples %>% filter(!(MCoVNumber %in% duplicated_mcov_numbers))
#sample collection dates, run IDs, and Houston call on quality ('low quality' means 5% or more Ns)
dates_and_runs<-read.csv("4_mcov_strain_variant_map_covid_pangolin_db_input_run_65.csv") %>% separate(COLLECTION_DT, into=c("COLLECTION_DT","time"), sep=" ") %>% select(MCoVNumber, COLLECTION_DT, quality, run_id_final) %>% mutate(COLLECTION_DT=as.Date(COLLECTION_DT, "%m/%d/%y"), MCoVNumber=str_remove(MCoVNumber,"-"))
#qPCR instrument and Ct value obtained in Houston
#Aptima instrument calculates relative light units, not CT -- adjust columns accordingly
ct_data<-read.csv("ct_instrument_data_update.csv") %>% mutate(MCoVNumber=str_remove(MCoVNumber,"-")) %>% select(MCoVNumber, INSTRUMENT, CT=CT_RESULT) %>% mutate(CT=as.numeric(CT)) %>% mutate(RLU=if_else(INSTRUMENT=="APTIMA", CT, NA_real_)) %>% mutate(CT=if_else(is.na(RLU), CT, NA_real_)) %>% mutate(CT=as.numeric(CT), RLU=as.numeric(RLU))
#percentage of sites with at least 100x coverage in each sample
coverage_100x<-read.csv("all_samples_coverage_100x_revised.csv")%>% select(MCoVNumber=samplename, fraction_100x_coverage)
sample_info<-left_join(dates_and_runs, ct_data) %>% left_join(coverage_100x)
Joining, by = "MCoVNumber"
Joining, by = "MCoVNumber"
mcov_samples_with_info<-left_join(mcov_samples, sample_info) %>% filter(!is.na(COLLECTION_DT)) #samples without dates in database confirmed not to have date info; exclude
Joining, by = "MCoVNumber"
Filtering samples
Several steps of QC filtering to get to final working_samples list of included samples
#Keep only samples from Dec 2020 through July 2021 and with 100x coverage over 95% of genome. Exclude samples from runs 20 and 21 or classified as low quality
working_samples <- mcov_samples_with_info %>% filter(COLLECTION_DT>"2020-11-30" & COLLECTION_DT<"2021-08-01") %>% filter(fraction_100x_coverage>=0.95) %>% filter(quality!="LQ") %>% filter(!(run_id_final %in% c("Run_20","Run_21"))) %>% filter(pango_lineage!="None")
#Identify samples coming from the same patient; keep only the earliest sample from patient
#identify samples coming from the same patient
p_list<-read.csv("patientID_mcov.csv") %>% mutate(MCoVNumber=str_remove(MCoVNumber, "-")) %>% select(MCoVNumber, PatientID)
multi_sample_patients <- working_samples %>% left_join(p_list) %>% filter(duplicated(PatientID)) %>% pull(PatientID) %>% unique()
Joining, by = "MCoVNumber"
samples_to_dedup<-p_list %>% filter(PatientID %in% multi_sample_patients) %>% pull(MCoVNumber)
list_to_dedup<-working_samples %>% filter(MCoVNumber %in% samples_to_dedup) %>% left_join(p_list)
Joining, by = "MCoVNumber"
#list to include including the randomly chosen ones from same-day samples is saved:
dedup_multi<-read.csv("dedup_early.csv") %>% pull(x)
drop_multi<-setdiff(samples_to_dedup, dedup_multi)
working_samples<-working_samples %>% filter(!(MCoVNumber %in% drop_multi))
#run consensus sequences through Nextclade QC; exclude samples where consensus sequence was scored as "bad"
bad_samples<-read.csv("houston_nextclade.tsv", sep='\t') %>% filter(startsWith(seqName, "MCoV")) %>% mutate(MCoVNumber=regmatches(seqName, regexpr("MCoV.[0-9]+", seqName)) %>% str_remove("-") %>% str_remove("_")) %>% filter(qc.overallStatus=="bad" | qc.overallStatus=="") %>% pull(MCoVNumber)
working_samples<-working_samples %>% filter(!MCoVNumber %in% bad_samples)
#lump lineages represented by less than 20 samples into an Other category
working_samples %>% group_by(pango_lineage) %>% summarise(n=n()) %>% filter(n>=20) %>% pull(pango_lineage) -> lineages_over_20
working_samples$pango_lineage_c<-if_else(working_samples$pango_lineage %in% lineages_over_20, working_samples$pango_lineage, "Other")
#bin lineages by collection month
working_samples <- working_samples %>% mutate(collection_month=format(as.Date(COLLECTION_DT), "%Y-%m"))
#samples by collection month and sequencing run
table(working_samples$run_id_final, working_samples$collection_month)
2020-12 2021-01 2021-02 2021-03 2021-04 2021-05 2021-06 2021-07
Run_11 4 539 0 0 0 0 0 0
Run_12 194 262 0 0 0 0 0 0
Run_13 0 600 0 0 0 0 0 0
Run_15 63 442 0 0 0 0 0 0
Run_16 0 469 0 0 0 0 0 0
Run_18 0 287 144 0 0 0 0 0
Run_19 10 104 335 0 0 0 0 0
Run_22 0 114 261 0 0 0 0 0
Run_23 0 345 102 0 0 0 0 0
Run_24 290 180 1 56 0 0 0 0
Run_25 0 0 248 193 0 0 0 0
Run_26 334 0 0 158 0 0 0 0
Run_27 263 0 17 198 0 0 0 0
Run_28 336 0 0 156 0 0 0 0
Run_29 349 0 0 150 0 0 0 0
Run_30 342 1 0 89 0 0 0 0
Run_31 275 0 0 139 0 0 0 0
Run_32 474 10 0 0 0 0 0 0
Run_33 277 0 0 22 142 0 0 0
Run_34 308 0 0 0 61 0 0 0
Run_35 245 0 0 0 111 0 0 0
Run_36 0 0 0 0 59 0 0 0
Run_37 0 0 0 0 184 0 0 0
Run_39 0 0 0 0 198 0 0 0
Run_40 0 0 0 0 174 37 0 0
Run_41 0 0 0 0 3 138 0 0
Run_43 0 0 0 0 0 212 0 0
Run_44 0 0 0 0 0 100 0 0
Run_46 0 0 0 0 0 149 0 0
Run_48 0 0 0 0 0 1 75 0
Run_49 0 0 0 0 0 0 98 0
Run_51 0 0 0 0 0 0 107 0
Run_52 0 0 0 0 0 0 45 79
Run_53 0 0 0 0 0 0 0 219
Run_57 0 0 0 0 0 0 0 309
Run_58 0 0 0 0 0 0 0 308
Run_59 0 0 0 0 0 0 0 324
Run_61 0 0 0 0 0 0 0 571
#how does filtering affect the distribution of CT values?
mcov_samples_with_info %>% pull(CT) %>% median(na.rm=TRUE) #before filtering
[1] 28.4
working_samples %>% pull(CT) %>% median(na.rm=TRUE) #after filtering
[1] 20.915
#distributions of CT values before and after filtering
ct_allsamples<-mcov_samples_with_info %>% filter(INSTRUMENT %in% c("ALINITY","PANTHER")) %>% ggplot(aes(x=CT)) + geom_histogram(binwidth=2) + facet_wrap(~INSTRUMENT) + theme_bw() + theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.position = c(0.8,0.7), legend.text=element_text(size=16), legend.title=element_text(size=14)) + labs(caption="Before exclusion criteria")
ct_workingsamples<-working_samples %>% filter(INSTRUMENT %in% c("ALINITY","PANTHER")) %>% ggplot(aes(x=CT)) + geom_histogram() + facet_wrap(~INSTRUMENT) + theme_bw() + theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.position = c(0.8,0.7), legend.text =element_text(size=16), legend.title=element_text(size=14)) + labs(caption="After exclusion criteria")
ct_histograms<-plot_grid(ct_allsamples, ct_workingsamples, nrow=2, labels=NA)
Warning: Removed 5 rows containing non-finite values (stat_bin).
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
#effect of breadth/depth of coverage on minor variant detection
mcov_samples_list<-mcov_samples_with_info %>% select(MCoVNumber, fraction_100x_coverage)
n_var_coverage<-read.csv("variant_sites_threshold.csv") %>% group_by(MCoVNumber) %>% summarise(n_var=n()) %>% right_join(mcov_samples_list) %>% mutate(n_var=replace_na(n_var,0),coverage_group=cut(fraction_100x_coverage, breaks= c(0,0.65,0.95,1), right=FALSE)) %>% ggplot(aes(x=coverage_group, y=n_var)) + geom_boxplot(outlier.alpha = 0.5, outlier.size=0.5) + xlab("Fraction of genome with at least 100x coverage") + ylab("Number of minor variants detected") + theme_bw() + theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.position = c(0.8,0.7), legend.text =element_text(size=16), legend.title=element_text(size=14))
Joining, by = "MCoVNumber"
#FIGURE S1
plot_grid(n_var_coverage, ct_histograms, labels="auto", ncol=2)
Warning: Removed 1 rows containing missing values (geom_text).

Gene and primer positions
read.csv("nCoV-2019.artic_v3.primer.txt", sep="\t", header=FALSE) %>% select(start=V2, end=V3) -> primers
primer_positions<-as.numeric()
for (i in 1:nrow(primers)){
primer_positions<-c(primer_positions, primers[i,]$start:primers[i,]$end)
}
#gene positions
genes<-read.csv("ntpos_gene_update.csv") %>% mutate(gene_id=as.factor(gene_id))
genes %>% arrange(ntpos) %>% pull(gene_id) %>% unique() -> gene_names
genes$gene_id <- factor(genes$gene_id, levels=gene_names)
genes %>% group_by(gene_id) %>% summarise(gene_length=n()) -> gene_lengths
Consensus lineage changes over time
# get numbers of each lineage and totals per day
lineages_dates<-working_samples %>% group_by(COLLECTION_DT, pango_lineage) %>% summarise(n_cases=n()) %>% pivot_wider(id_cols=COLLECTION_DT, names_from=pango_lineage, values_from=n_cases)
`summarise()` has grouped output by 'COLLECTION_DT'. You can override using the `.groups` argument.
total_cases<-lineages_dates %>% ungroup %>% select(!COLLECTION_DT) %>% rowSums(na.rm=TRUE)
lineages_dates$total_cases<-total_cases
consensus_lineage_by_date<-lineages_dates %>% pivot_longer(cols=-1, names_to="lineage", values_to="cases") %>% mutate(cases=replace_na(cases,0))
# a list of daily case numbers
daily_cases<-consensus_lineage_by_date %>% filter(lineage=="total_cases") %>% select(COLLECTION_DT, cases)
#FIGURE 1
consensus_lineage_by_date %>% filter(lineage %in% c("total_cases","B.1.2","B.1.1.7","B.1.617.2")) %>% ggplot(aes(x=COLLECTION_DT, y=cases, color=lineage)) + geom_line() +
scale_color_manual(values=c("#000000", "#46ACC8", "#E58601", "#B40F20"),
limits=c("total_cases", "B.1.2", "B.1.1.7","B.1.617.2"),
labels=c("Total samples","B.1.2","B.1.1.7","B.1.617.2")) + scale_x_date(minor_breaks = "1 month") +
theme_bw() + xlab("Collection Date (2020-2021)") + ylab("Number of samples") + theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.position = c(0.8,0.7), legend.text =element_text(size=12), legend.title=element_text(size=14)) + labs(color=NULL)

Total minor variant richness
#file collecting all sites in samples that have minor variants detected at any frequency, at sites with at least 100 reads
all_variant_sites<-read.csv("variant_sites_all.csv")
zero_variant_samples<-read.csv("zerovar.csv") %>% select(name=x) %>% mutate(ntpos=NA, major=NA, majorfreq=NA, minor=NA, minorfreq=NA, totalcount=NA, binocheck=NA, MCoVNumber=name)
all_variant_sites<-rbind(all_variant_sites, zero_variant_samples) %>% select(MCoVNumber, ntpos, major, minor, minorfreq, totalcount)
#keeping only sites meeting minor variant threshold criteria
variant_sites_threshold<-all_variant_sites %>%
filter(minorfreq>=0.03 & minorfreq*totalcount>=10) %>%
filter(major %in% c("A","T","G","C")) %>%
filter(minor %in% c("A","T","G","C")) %>%
filter(!(ntpos %in% primer_positions))
sample_list<-working_samples %>% select(MCoVNumber) %>% unique()
counts<-variant_sites_threshold %>% group_by(MCoVNumber) %>% summarise(n_var=n())
var_list<-left_join(sample_list, counts) %>% mutate(n_var=replace_na(n_var, 0))
Joining, by = "MCoVNumber"
samples_n_var<-left_join(working_samples, var_list)
Joining, by = "MCoVNumber"
median(samples_n_var$n_var)
[1] 2
median(filter(samples_n_var, CT<=25)$n_var)
[1] 1
nrow(filter(samples_n_var, n_var<10)) / nrow(samples_n_var)
[1] 0.7579832
var_by_ct_fig<-samples_n_var %>% filter(INSTRUMENT %in% c("ALINITY","PANTHER")) %>% ggplot(aes(x=CT, y=n_var)) + geom_point(alpha=0.5) + facet_grid(~INSTRUMENT)+ theme_bw() + stat_smooth(color="#46ACC8") + theme_bw() + xlab("CT value") + ylab("No. minor variants") + theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.position = c(0.8,0.7), legend.text =element_text(size=16), legend.title=element_text(size=14), strip.background =element_rect(fill="#E2D200"))
samples_n_var_fig<-samples_n_var %>% ggplot(aes(x=n_var)) + geom_histogram(binwidth=10,fill="#B40F20") + theme_bw() + xlab("Number of minor variant sites in sample") + ylab("Number of samples") + theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.position = c(0.8,0.7), legend.text =element_text(size=16), legend.title=element_text(size=14))
#FIGURE 2
ggdraw(samples_n_var_fig + theme_half_open(12)) +
draw_plot(var_by_ct_fig, .3, .3, .6, .6) +
draw_plot_label(
c("a", "b"),
c(0, 0.45),
c(1, 0.95),
size = 12
)
`geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'

Reproducibility of ad hoc samples
all_replicates_table<-read.csv("replicated_samples.csv")
#check for too many mismatches on the consensus level
all_replicates_table %>%
mutate(high_confidence_site=if_else(major.original %in% c("A","C","T","G") &
major.original %in% c("A","C","T","G") &
totalcount.original>100 &
totalcount.reseq>100 &
majorfreq.original>0.9 &
majorfreq.reseq>0.9,1,0,missing=0)) %>%
mutate(consensus_mismatch=if_else(high_confidence_site==1 & major.original!=major.reseq,1,0)) %>% group_by(MCoVNumber) %>% summarise(consensus_mismatches=sum(consensus_mismatch)) %>% arrange(desc(consensus_mismatches)) %>%
filter(consensus_mismatches>2) %>% pull(MCoVNumber) -> consensus_mismatch_samples
all_replicates_table_filt<-all_replicates_table %>% filter(!(MCoVNumber %in% consensus_mismatch_samples))
minors_table<-all_replicates_table_filt %>% filter(major.original %in% c("A","C","T","G")) %>% filter(minor.original %in% c("A","C","T","G")) %>%
filter(totalcount.original>100 & minorfreq.original>=0.03 & totalcount.original*minorfreq.original>=10 & tolower(binocheck.original)!="false") %>% filter((!ntpos %in% primer_positions))
#number of minor variants originally and how many are reproducible
minors_table %>% mutate(recovered_minor=if_else(minor.original==minor.reseq,1,0,missing=0)) %>% group_by(MCoVNumber) %>% summarise(n_var_original=n(), n_var_reproducible=sum(recovered_minor))->samples_n_var_reproducible
reprod_samples<-select(all_replicates_table, MCoVNumber) %>% filter(!duplicated(MCoVNumber)) %>% filter(!(MCoVNumber %in% consensus_mismatch_samples)) %>% left_join(samples_n_var_reproducible) %>% mutate(n_var_original=replace_na(n_var_original, 0), n_var_reproducible=replace_na(n_var_reproducible, 0))
Joining, by = "MCoVNumber"
reprod_samples %>% filter(n_var_reproducible>=3) %>% pull(MCoVNumber) -> samples_3rep #samples with at least 3 reproducible variants, for comparing frequencies later
#what's the median number of reproducible minor variants?
reprod_samples %>% pull(n_var_original) %>% median(na.rm=TRUE)
[1] 120
reprod_samples %>% pull(n_var_reproducible) %>% median(na.rm=TRUE)
[1] 18
minors_table<-minors_table %>% mutate(recovered_minor=if_else(minor.original==minor.reseq,1,0,missing=0))
labels <- c(`0` = "Non-reproducible site", `1` = "Reproducible site")
depths_rep<-minors_table %>% ggplot(aes(x=totalcount.original, y=minorfreq.original)) + geom_point(alpha=0.5) +
facet_grid(recovered_minor~., labeller=labeller(recovered_minor = labels)) +
xlab("Read depth at site in first replicate") + ylab("MAF at site in first replicate") +
theme_bw() +
theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.position = c(0.8,0.7), legend.text =element_text(size=16), legend.title=element_text(size=14))
compare_var_distributions<-reprod_samples %>% select(MCoVNumber, n_var_original, n_var_reproducible) %>% pivot_longer(2:3, names_to="variant_type", values_to="n")
labels <- c(n_var_original = "Variants in first replicate", n_var_reproducible = "Reproducible variants")
distributions_rep<-compare_var_distributions %>% ggplot(aes(x=n)) + geom_histogram(binwidth=10) + facet_grid(variant_type~., labeller=labeller(variant_type = labels)) + xlab("Number of minor variant sites in sample") + ylab("Number of samples") + theme_bw() + theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.position = c(0.8,0.7), legend.text =element_text(size=16), legend.title=element_text(size=14))
maf_rep<-minors_table %>% mutate(recovered_minor=if_else(minor.original==minor.reseq,1,0,missing=0)) %>% filter(recovered_minor==1) %>% ggplot(aes(x=minorfreq.original, y=minorfreq.reseq)) + geom_point(alpha=0.5) +
xlab("MAF in first replicate") + ylab("MAF in second replicate") +
theme_bw() +
theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.position = c(0.8,0.7), legend.text =element_text(size=16), legend.title=element_text(size=14))
maf_r2<-minors_table %>% filter(MCoVNumber %in% samples_3rep) %>% filter(recovered_minor==1) %>% left_join(working_samples) %>% group_by(MCoVNumber) %>% summarise(Ct=max(CT), r2=summary(lm(minorfreq.reseq~minorfreq.original))$r.squared) %>% filter(Ct<50) %>% ggplot(aes(x=Ct, y=r2)) + geom_point(alpha=0.5) + theme_bw() +
xlab("Ct value") + ylab(expression(paste(R^2, " MAF in first and second replicate"))) +
theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.position = c(0.8,0.7), legend.text =element_text(size=16), legend.title=element_text(size=14))
Joining, by = "MCoVNumber"
maf_corr_examples<-minors_table %>% mutate(recovered_minor=if_else(minor.original==minor.reseq,1,0,missing=0)) %>% filter(recovered_minor==1) %>% filter(MCoVNumber %in% sample(unique(minors_table$MCoVNumber), size=6, replace=FALSE)) %>% ggplot(aes(x=minorfreq.original, y=minorfreq.reseq)) + geom_point(alpha=0.5) + theme_bw() + facet_wrap(~MCoVNumber) + theme(axis.text.x=element_text(size=12, angle=90), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14)) + xlab("MAF in first replicate") + ylab("MAF in second replicate")
maf_rep_all<-plot_grid(maf_rep, plot_grid(maf_corr_examples, maf_r2, nrow=2), ncol=2)
labels <- c(`0` = "Non-reproducible variants", `1` = "Reproducible variants")
shared_rep<-minors_table %>% ggplot(aes(x=ntpos)) + geom_bar(color="black") + facet_grid(recovered_minor~., labeller=labeller(recovered_minor = labels)) + theme_bw() + xlab("Nucleotide position") + ylab("No. samples with minor variant at position") + theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.position = c(0.8,0.7), legend.text =element_text(size=16), legend.title=element_text(size=14)) + annotate("rect", xmin=27894, xmax=28295, ymin=0, ymax=Inf, alpha=0.1) + annotate("rect", xmin=28274, xmax=29533, ymin=0, ymax=Inf, alpha=0.1)
reproducible_mutations <- minors_table %>% filter(recovered_minor==1) %>% select(MCoVNumber,ntpos, major=major.original,minor=minor.original)
non_reproducible_mutations <- minors_table %>% filter(recovered_minor==0) %>% select(MCoVNumber,ntpos, major=major.original,minor=minor.original)
genes_rep<-reproducible_mutations %>% left_join(genes) %>% group_by(gene_id) %>% summarise(n=n()) %>% filter(gene_id!="") %>% left_join(gene_lengths) %>% mutate(density=n/gene_length) %>% ggplot(aes(x=gene_id, y=density)) + geom_bar(stat="identity", fill="white", color="black") + theme_bw() + theme(axis.text.x=element_text(size=12, angle=90), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.position = c(0.8,0.7), legend.text =element_text(size=16), legend.title=element_text(size=14)) + xlab("Gene") + ylab("Density of reproducible minor variants")
Joining, by = "ntpos"
Joining, by = "gene_id"
plot_grid(plot_grid(plot_grid(depths_rep, distributions_rep, nrow=2, labels=c("A","B")), plot_grid(shared_rep, genes_rep, nrow=2, rel_heights=c(2,1)),ncol=2, labels=c(NA,"C")), maf_rep_all, ncol=2, labels=c(NA,"D"))
Warning: Removed 1 rows containing missing values (geom_text).
Warning: Removed 1 rows containing missing values (geom_text).

a<-plot_grid(depths_rep, shared_rep, distributions_rep, genes_rep, nrow=2, labels=c("a","c","b","d"))
b<-plot_grid(maf_rep, maf_corr_examples, maf_r2, nrow=3, labels=c("e","f","g"))
#FIGURE S2
plot_grid(a, b, ncol=2, rel_widths=c(1.5,1))

Clinical correlates of minor variant richness
#samples for which we have patient info
pds<-read.csv("MCoV_patient_information.csv") %>% mutate(chronic_lung_disease=as.factor(chronic_lung_disease), chronic_liver_disease=as.factor(chronic_liver_disease), chronic_kidney_disease=as.factor(chronic_kidney_disease), chronic_heart_disease=as.factor(chronic_heart_disease), hypertension=as.factor(hypertension), diabetes=as.factor(diabetes), hiv=as.factor(hiv), cancer=as.factor(cancer), obesity=as.factor(obesity), transplant=as.factor(transplant), plasma=as.factor(plasma), mAb=as.factor(mAb), admitted_hospital=as.factor(admitted_hospital))
#filter out run 13 because of suspected high contamination
pds<-pds %>% left_join(working_samples) %>% filter(run_id_final!="Run_13")
Joining, by = "MCoVNumber"
#low ct samples only
p<-pds %>% left_join(samples_n_var) %>% filter(CT<=24)
Joining, by = c("MCoVNumber", "pango_lineage", "COLLECTION_DT", "quality", "run_id_final", "INSTRUMENT", "CT", "RLU", "fraction_100x_coverage", "pango_lineage_c", "collection_month")
summary(p$n_var)
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.000 0.000 1.000 2.549 2.000 166.000
#Random Forest model for classifying low-CT samples as having high or low minor variant richness
p <- p %>% mutate(var_level=if_else(n_var<=2, "low","high")) %>% mutate(var_level=as.factor(var_level)) %>% mutate(chronic_illness=if_else(chronic_lung_disease==1 | chronic_heart_disease==1 | chronic_kidney_disease==1 | chronic_liver_disease==1 | diabetes==1,1,0))
p_select <- p %>% select(age_group, sex, ethnicity, chronic_lung_disease, chronic_liver_disease, chronic_kidney_disease, chronic_heart_disease, hypertension, diabetes, hiv, cancer, obesity, transplant, plasma, mAb, admitted_hospital, vaccine_status_group, var_level)
p.rf<-randomForest(var_level~.,
data=p_select,
ntree=1000,
mtry=5,
importance = T)
importance.randomForest <- as.data.frame(randomForest::importance(p.rf))
importance.randomForest<-importance.randomForest %>% arrange(desc(MeanDecreaseAccuracy))
importance.randomForest
rf.roc<-roc(p_select$var_level,p.rf$votes[,2], levels=c(case="high",control="low"))
Setting direction: controls < cases
auc(rf.roc)
Area under the curve: 0.561
#RF model performance is poor overall, but hospital admission is most important factor - are high-variant samples overrepresented among patients requiring hospitalization?
table(p$admitted_hospital, p$var_level)
high low
0 497 2258
1 451 1043
chisq.test(table(p$admitted_hospital, p$var_level))
Pearson's Chi-squared test with Yates' continuity correction
data: table(p$admitted_hospital, p$var_level)
X-squared = 81.767, df = 1, p-value < 2.2e-16
#which patient factors are associated with hospitalization?
glm(admitted_hospital ~ chronic_heart_disease + chronic_lung_disease + chronic_liver_disease + chronic_kidney_disease + cancer + transplant + hiv + hypertension + diabetes + obesity + age_group + sex, data=pds, family="binomial") %>% summary()
Call:
glm(formula = admitted_hospital ~ chronic_heart_disease + chronic_lung_disease +
chronic_liver_disease + chronic_kidney_disease + cancer +
transplant + hiv + hypertension + diabetes + obesity + age_group +
sex, family = "binomial", data = pds)
Deviance Residuals:
Min 1Q Median 3Q Max
-2.4490 -0.9002 -0.6482 1.0058 3.2922
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -5.07721 0.45003 -11.282 < 2e-16 ***
chronic_heart_disease1 0.73903 0.05249 14.080 < 2e-16 ***
chronic_lung_disease1 0.15448 0.06416 2.408 0.0161 *
chronic_liver_disease1 0.02851 0.08502 0.335 0.7374
chronic_kidney_disease1 0.91194 0.08382 10.880 < 2e-16 ***
cancer1 -0.03106 0.08661 -0.359 0.7199
transplant1 -0.66787 0.34912 -1.913 0.0557 .
hiv1 0.34300 0.34172 1.004 0.3155
hypertension1 -0.33769 0.05695 -5.929 3.04e-09 ***
diabetes1 0.49217 0.05476 8.987 < 2e-16 ***
obesity1 0.55164 0.04189 13.167 < 2e-16 ***
age_group18-54 3.62389 0.45063 8.042 8.85e-16 ***
age_group55-64 4.24285 0.45245 9.377 < 2e-16 ***
age_group65+ 4.72090 0.45231 10.437 < 2e-16 ***
sexM 0.42609 0.04054 10.510 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 17110 on 12486 degrees of freedom
Residual deviance: 14383 on 12472 degrees of freedom
AIC: 14413
Number of Fisher Scoring iterations: 7
#individual comorbidities will be difficult to disentangle from hospitalization - continue to treat hospitalization as broad indicator
#does hospitalization effect still exist taking into account CT value and sequencing run?
lme(log(n_var+1) ~ CT*admitted_hospital, random=~1|run_id_final,
data=p) %>% anova()
#expanding to include CT values >24
pds %>% left_join(samples_n_var) %>% filter(!is.na(CT)) %>% lme(data=., log10(n_var + 1)~CT*admitted_hospital, random=~1|run_id_final) %>% anova()
Joining, by = c("MCoVNumber", "pango_lineage", "COLLECTION_DT", "quality", "run_id_final", "INSTRUMENT", "CT", "RLU", "fraction_100x_coverage", "pango_lineage_c", "collection_month")
#FIGURE 3A
hospital_ct_all<-pds %>% left_join(samples_n_var) %>% filter(!is.na(CT)) %>% ggplot(aes(x=CT, y=log(n_var+1), fill=admitted_hospital)) + geom_point(shape=21, alpha=0.5)+stat_smooth(method=lm, aes(color=admitted_hospital)) + theme_bw() + scale_fill_manual(values=c("lightgray","#B40F20"), labels=c("Not hospitalized","Hospitalized")) + scale_color_manual(values=c("darkgray","#B40F20"),labels=c("Not hospitalized","Hospitalized")) + theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.text=element_text(size=16), legend.position="bottom", legend.direction="vertical", legend.title=element_blank()) + xlab("CT value") + ylab("Log10(No. minor variants + 1)")
Joining, by = c("MCoVNumber", "pango_lineage", "COLLECTION_DT", "quality", "run_id_final", "INSTRUMENT", "CT", "RLU", "fraction_100x_coverage", "pango_lineage_c", "collection_month")
hospital_ct_all
`geom_smooth()` using formula 'y ~ x'

lme(data=surv_comp, log10(n_var + 1)~CT*surveillance_sample, random=~1|run_id_final) %>% anova()
lme(data=surv_comp, log10(n_var + 1)~CT*surveillance_sample, random=~1|run_id_final) %>% anova()
lme(data=vax_comp, log10(n_var + 1)~CT*vaccine_status_group, random=~1|run_id_final) %>% anova()
lme(data=vax_comp, log10(n_var + 1)~CT*vaccine_status_group, random=~1|run_id_final) %>% anova()
#FIGURE 3: minor variant richness in patients requiring hospitalization; asymptomatic healthcare workers; vaccinated patients
plot_grid(hospital_ct_all, surveillance_ct, vax_ct, ncol=3, align="hv", labels="auto")
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'

#Figure S3: minor variant richness in patients requiring hospitalization; asymptomatic healthcare workers; vaccinated patients, separated by low/high CT samples
hosp_ct_low<-pds %>% left_join(samples_n_var) %>% filter(!is.na(CT)) %>% filter(CT<=24) %>% ggplot(aes(x=CT, y=log(n_var+1), fill=admitted_hospital)) + geom_point(shape=21, alpha=0.5)+stat_smooth(method=lm, aes(color=admitted_hospital)) + theme_bw() + scale_fill_manual(values=c("lightgray","#B40F20"), labels=c("Not hospitalized","Hospitalized")) + scale_color_manual(values=c("darkgray","#B40F20"),labels=c("Not hospitalized","Hospitalized")) + theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.text=element_text(size=16), legend.position="bottom", legend.direction="vertical", legend.title=element_blank()) + xlab("CT value") + ylab("Log10(No. minor variants + 1)")
Joining, by = c("MCoVNumber", "pango_lineage", "COLLECTION_DT", "quality", "run_id_final", "INSTRUMENT", "CT", "RLU", "fraction_100x_coverage", "pango_lineage_c", "collection_month")
hosp_ct_high<-pds %>% left_join(samples_n_var) %>% filter(!is.na(CT)) %>% filter(CT>24)%>% ggplot(aes(x=CT, y=log(n_var+1), fill=admitted_hospital)) + geom_point(shape=21, alpha=0.5)+stat_smooth(method=lm, aes(color=admitted_hospital)) + theme_bw() + scale_fill_manual(values=c("lightgray","#B40F20"), labels=c("Not hospitalized","Hospitalized")) + scale_color_manual(values=c("darkgray","#B40F20"),labels=c("Not hospitalized","Hospitalized")) + theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.text=element_text(size=16), legend.position="bottom", legend.direction="vertical", legend.title=element_blank()) + xlab("CT value") + ylab("Log10(No. minor variants + 1)")
Joining, by = c("MCoVNumber", "pango_lineage", "COLLECTION_DT", "quality", "run_id_final", "INSTRUMENT", "CT", "RLU", "fraction_100x_coverage", "pango_lineage_c", "collection_month")
hcw_ct_low<- surv_comp %>% filter(CT<=24) %>% ggplot(aes(x=CT, y=log(n_var+1), fill=surveillance_sample)) + geom_point(shape=21, alpha=0.5)+stat_smooth(method=lm, aes(color=surveillance_sample)) + theme_bw() + scale_fill_manual(values=c("lightgray","#E58601")) + scale_color_manual(values=c("darkgray","#E58601")) + theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.text=element_text(size=16), legend.position="bottom", legend.direction="vertical", legend.title=element_blank()) + xlab("CT value") + ylab("Log10(No. minor variants + 1)")
hcw_ct_high<-surv_comp %>% filter(CT>24) %>% ggplot(aes(x=CT, y=log(n_var+1), fill=surveillance_sample)) + geom_point(shape=21, alpha=0.5)+stat_smooth(method=lm, aes(color=surveillance_sample)) + theme_bw() + scale_fill_manual(values=c("lightgray","#E58601")) + scale_color_manual(values=c("darkgray","#E58601")) + theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.text=element_text(size=16), legend.position="bottom", legend.direction="vertical", legend.title=element_blank()) + xlab("CT value") + ylab("Log10(No. minor variants + 1)")
vax_ct_low<-vax_comp %>% filter(CT<=24) %>% ggplot(aes(x=CT, y=log(n_var+1), fill=vaccine_status_group)) + geom_point(shape=21, alpha=0.5)+stat_smooth(method=lm, aes(color=vaccine_status_group)) + theme_bw() + scale_fill_manual(values=c("lightgray","#46ACC8")) + scale_color_manual(values=c("darkgray","#46ACC8")) + theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.text=element_text(size=16), legend.position="bottom", legend.direction="vertical", legend.title=element_blank()) + xlab("CT value") + ylab("Log10(No. minor variants + 1)")
vax_ct_high<-vax_comp %>% filter(CT>24) %>% ggplot(aes(x=CT, y=log(n_var+1), fill=vaccine_status_group)) + geom_point(shape=21, alpha=0.5)+stat_smooth(method=lm, aes(color=vaccine_status_group)) + theme_bw() + scale_fill_manual(values=c("lightgray","#46ACC8")) + scale_color_manual(values=c("darkgray","#46ACC8")) + theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.text=element_text(size=16), legend.position="bottom", legend.direction="vertical", legend.title=element_blank()) + xlab("CT value") + ylab("Log10(No. minor variants + 1)")
plot_grid(hosp_ct_low, hosp_ct_high, hcw_ct_low, hcw_ct_high, vax_ct_low, vax_ct_high, nrow=3, labels="AUTO")
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'

#LASSO regression model using glmnet package
#include CT, run, pango lineage
ps<-pds %>% left_join(samples_n_var) %>% filter(!is.na(CT)) %>% filter(!is.na(surveillance_sample))
Joining, by = c("MCoVNumber", "pango_lineage", "COLLECTION_DT", "quality", "run_id_final", "INSTRUMENT", "CT", "RLU", "fraction_100x_coverage", "pango_lineage_c", "collection_month")
y<-log10(ps$n_var+1)
x<-data.matrix(ps[, c('age_group', 'sex', 'ethnicity', 'chronic_lung_disease', 'chronic_liver_disease', 'chronic_kidney_disease', 'chronic_heart_disease', 'hypertension', 'diabetes', 'cancer', 'obesity', 'transplant', 'plasma', 'mAb', 'admitted_hospital', 'vaccine_status_group', 'pango_lineage_c', 'CT', 'run_id_final', 'collection_month', 'surveillance_sample')])
cv_model <- cv.glmnet(x, y, alpha = 1)
plot(cv_model)

best_model <- glmnet(x, y, alpha = 1, lambda = cv_model$lambda.min)
best_model$dev.ratio
[1] 0.4328378
#FIG S4
coef(best_model) %>% as.matrix() %>% data.frame() %>% rownames_to_column() %>% rename(factor=rowname, coefficient=s0) %>% filter(factor!="(Intercept)") %>% arrange(desc(coefficient)) %>% ggplot(aes(x=coefficient, y=fct_reorder(factor,coefficient))) + geom_bar(stat="identity", fill="#E2D200", color="black") + theme_bw() + theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.position = c(0.8,0.7), legend.text =element_text(size=16), legend.title=element_text(size=14)) + ylab("factor")

Examining highly shared sites
gene_limits<-genes %>% group_by(gene_id) %>% summarise(start=min(ntpos), end=max(ntpos)) %>% filter(gene_id!="") %>% mutate(molecule="")
gene_arrows<-ggplot(gene_limits, aes(xmin = start, xmax = end, y=molecule, label = gene_id)) +
geom_gene_arrow(arrowhead_height = unit(3, "mm"), arrowhead_width = unit(1, "mm")) + geom_gene_label() + geom_segment(aes(x=266,y=1.5,xend=13468,yend=1.5), size=0.2) + annotate("text", label="ORF1a", x=5000, y=1.41, size=3) + geom_segment(aes(x=13468,y=1.4,xend=21555,yend=1.4), size=0.2) + annotate("text", label="ORF1b", x=18000, y=1.31, size=3) +
theme_genes() + ylab(NULL) + xlab(NULL)
#How does diversity at consensus level relate to diversity at minor level?
consensus_change_list<-read.csv("all_consensus_minority_changes.csv") %>% mutate(MCoVNumber=regmatches(name, regexpr("[M,R,S,O]CoV.[0-9]+", name)) %>% str_remove("-") %>% str_remove("_")) %>% filter(MCoVNumber %in% working_samples$MCoVNumber) %>% filter(!ntpos %in% primer_positions) %>% filter(major!=refnt) %>% left_join(working_samples) #list of consensus changes
Joining, by = "MCoVNumber"
consensus_variants_by_ntpos<-consensus_change_list %>% group_by(ntpos) %>% summarise(n_consensus=n()) %>% filter(!ntpos %in% primer_positions)
minor_variants_by_ntpos<-read.csv("variant_sites_threshold.csv") %>% filter(MCoVNumber %in% working_samples$MCoVNumber) %>% left_join(working_samples) %>% group_by(ntpos) %>% summarise(n_minor=n())
Joining, by = "MCoVNumber"
consensus_minor_by_ntpos <- full_join(consensus_variants_by_ntpos,minor_variants_by_ntpos) %>% mutate(n_consensus=replace_na(n_consensus, 0), n_minor=replace_na(n_minor, 0)) %>% pivot_longer(cols=2:3, names_to="type", values_to="n")
Joining, by = "ntpos"
consensus_minor_by_ntpos$type<-factor(consensus_minor_by_ntpos$type, levels=c("n_minor","n_consensus"), labels=c("Minor variant present","Consensus change from reference"))
sites<-consensus_minor_by_ntpos %>% ggplot(aes(x=ntpos, y=n)) + geom_bar(stat="identity", color="black") + facet_grid(type~., scales="free") + theme_bw() + annotate("rect", xmin=27894, xmax=28295, ymin=0, ymax=Inf, alpha=0.2, fill="#85D4E3") + annotate("rect", xmin=28274, xmax=29533, ymin=0, ymax=Inf, alpha=0.2, fill="#F4B5BD") + annotate("rect", xmin=21563, xmax=25384, ymin=0, ymax=Inf, alpha=0.2, fill="#FAD77B")+ ylab("Number of samples") + xlab("Nucleotide position") + scale_x_continuous(minor_breaks=seq(from=0, to=30000, by=500)) + geom_hline(data = data.frame(yint=nrow(working_samples)*0.02,z="n_minor"), aes(yintercept = yint), linetype = "dotted")
#FIGURE 4
shared_sites<-plot_grid(gene_arrows, sites, nrow=2, align="hv", axis="btlr", rel_heights=c(1,6))
working_sites<-variant_sites_threshold %>% filter(MCoVNumber %in% working_samples$MCoVNumber) %>% left_join(working_samples) %>% mutate(mutation=paste0(major,ntpos,minor))
Joining, by = "MCoVNumber"
highly_shared_sites<-working_sites %>% group_by(ntpos) %>% summarise(samples_containing_minor=n()) %>% arrange(desc(samples_containing_minor)) %>% filter(samples_containing_minor>nrow(working_samples)*0.02) %>% pull(ntpos)
samples_per_run<-working_samples %>% group_by(run_id_final) %>% summarise(n_samples_in_run=n())
working_sites %>% filter(ntpos %in% highly_shared_sites) %>% pull(MCoVNumber) %>% unique() -> samples_containing_hss
hss_info<-working_sites %>% filter(ntpos %in% highly_shared_sites) %>% select(ntpos, mutation, minor) %>% filter(!duplicated(mutation)) %>% left_join(genes) %>% mutate(reversion_to_ancestral=if_else(minor==refnt,"yes","no")) %>% select(mutation, gene_id, reversion_to_ancestral)
Joining, by = "ntpos"
hss_aa<-read.csv("highly_shared_sites_aa.csv")
hss_aa$aa<-factor(hss_aa$aa, levels=c("ORF1a: T283", "ORF1a: N615", "ORF1a: K2059", "ORF1a: M2606", "ORF1a: S2625", "ORF1a: T3308", "ORF1a: L3352", "ORF1a: G3846", "ORF1b: Y446", "ORF1b: N1653", "ORF1b: L2267", "ORF1b: R2613", "S: Y144", "S: Q677", "S: P681", "ORF3a: Q57", "ORF8: H17", "ORF8: S24", "N: D3", "N: P67", "N: S194", "N: P199", "N: R203", "N: G204", "N: T391"))
hss<-working_sites %>% filter(ntpos %in% highly_shared_sites) %>% group_by(ntpos, mutation) %>% summarise(n=n()) %>% left_join(hss_info) %>% left_join(hss_aa) %>% ggplot(aes(x=mutation, y=n)) + facet_wrap(ntpos~aa, scales="free") + geom_bar(stat="identity", aes(fill=reversion_to_ancestral)) + scale_fill_manual(values=c("gray","black")) + theme_bw() + theme(axis.text.x=element_text(angle=90), legend.position=c(0.85,0.05)) + labs(fill="Reversion to ancestral allele") + ylab("No. samples with minor variant")
`summarise()` has grouped output by 'ntpos'. You can override using the `.groups` argument.
Joining, by = "mutation"
Joining, by = "ntpos"
#FIGURE S5
hss

#highly shared sites by run
highly_shared_by_run<-working_samples %>% filter(MCoVNumber %in% samples_containing_hss) %>% group_by(run_id_final) %>% summarise(containing_hss=n()) %>% left_join(samples_per_run) %>% pivot_longer(cols=2:3, names_to="type", values_to="n") %>% ggplot(aes(x=run_id_final, y=n, fill=type)) + geom_bar(stat="identity", position="dodge", color="black") + theme_bw() + theme(axis.text.x=element_text(angle=90), legend.position="bottom", legend.title=element_blank()) + scale_fill_manual(values=c("black","white"), labels=c("Containing highly shared minor variant(s)","Total")) + xlab("Run ID") + ylab("No. samples")
Joining, by = "run_id_final"
#B.1.2 characteristic sites by run
b.1.2_sites<-data.frame(ntpos=c(1059, 10319, 21304, 25563, 27964, 28472, 28869), b12.allele=c("T","T","T","T","T","T","T"))
b12_tallies<-working_samples %>% mutate(b12_present=if_else(pango_lineage=="B.1.2",1,0)) %>% group_by(run_id_final) %>% summarise(n_b12_in_run=sum(b12_present))
b12_run13_illustration<-working_sites %>% filter(ntpos %in% b.1.2_sites$ntpos) %>% left_join(genes) %>% filter(major=="T" & minor==refnt) %>% filter(pango_lineage=="B.1.2") %>% group_by(ntpos, run_id_final) %>% summarise(n=n()) %>% left_join(b12_tallies) %>% mutate(fraction_b12_with_reversion_minor=n/n_b12_in_run) %>% ggplot(aes(x=run_id_final, y=fraction_b12_with_reversion_minor)) + geom_bar(stat="identity") + facet_wrap(~ntpos) + theme_bw() + theme(axis.text.x=element_text(angle=90), axis.title.x=element_blank()) + ylab("Fraction of B.1.2 with ancestral allele in minority")
Joining, by = "ntpos"
`summarise()` has grouped output by 'ntpos'. You can override using the `.groups` argument.
Joining, by = "run_id_final"
#P681 alleles by run
run_list<-data.frame(run_id_final=unique(working_samples$run_id_final))
major_by_run<-read.csv("site_23604.csv") %>% mutate(MCoVNumber=regmatches(name, regexpr("MCoV.[0-9]+", name)) %>% str_remove("-") %>% str_remove("_")) %>% filter(MCoVNumber %in% mcov_samples_with_info$MCoVNumber) %>% left_join(mcov_samples_with_info) %>% filter(run_id_final %in% working_samples$run_id_final) %>% filter(major %in% c("A","C","T","G")) %>% group_by(run_id_final, major) %>% summarise(n=n()) %>% right_join(run_list)
Joining, by = "MCoVNumber"
`summarise()` has grouped output by 'run_id_final'. You can override using the `.groups` argument.
Joining, by = "run_id_final"
minor_by_run<-read.csv("site_23604.csv") %>% mutate(MCoVNumber=regmatches(name, regexpr("MCoV.[0-9]+", name)) %>% str_remove("-") %>% str_remove("_")) %>% filter(MCoVNumber %in% working_samples$MCoVNumber) %>% left_join(working_samples) %>% filter(totalcount>=100 & minorfreq>=0.03 & minorfreq * totalcount>=10 & minor %in% c("A","T","G","C")) %>% group_by(run_id_final, minor) %>% summarise(n=n()) %>% right_join(run_list)
Joining, by = "MCoVNumber"
`summarise()` has grouped output by 'run_id_final'. You can override using the `.groups` argument.
Joining, by = "run_id_final"
maj_fcs<-major_by_run %>% ggplot(aes(x=run_id_final, y=n, fill=major)) + geom_bar(stat="identity", position="stack") + theme_bw() + theme(axis.text.x=element_text(angle=90), axis.title.x=element_blank()) + xlab("Run") + ylab("No. samples") + labs(fill="consensus")
min_fcs<-minor_by_run %>% ggplot(aes(x=run_id_final, y=n, fill=minor)) + geom_bar(stat="identity", position="stack") + theme_bw() + theme(axis.text.x=element_text(angle=90), axis.title.x=element_blank()) + xlab("Run") + ylab("No. samples") + labs(fill="minor")
#FIGURE S6
plot_grid(plot_grid(b12_run13_illustration, highly_shared_by_run, nrow=2, labels=c("A","B")), plot_grid(maj_fcs, min_fcs, nrow=2, align="hv"), ncol=2, labels=c(NA, "C"))
Warning: Removed 2 rows containing missing values (position_stack).
Warning: Removed 1 rows containing missing values (geom_text).

Timing of detection of minor variants of phenotypically important sites
spike_snp_table<-read.csv("spike_mutations.csv")
spike_sites<-read.csv("all_consensus_minority_changes.csv") %>% mutate(MCoVNumber=regmatches(name, regexpr("MCoV.[0-9]+", name)) %>% str_remove("-") %>% str_remove("_")) %>% filter(MCoVNumber %in% working_samples$MCoVNumber) %>% filter(ntpos %in% spike_snp_table$ntpos)
samples_spike_presence_absence<-spike_sites %>% filter(!ntpos %in% primer_positions) %>% left_join(spike_snp_table) %>% mutate(consensus_change=if_else(major==allele,1,0)) %>%
mutate(minor_change=if_else(totalcount>=100 & minorfreq>=0.03 &totalcount*minorfreq>=10 & tolower(binocheck)!="false" &
minor==allele, 1,0)) %>% select(mutation, MCoVNumber, consensus_change,minor_change) %>% left_join(working_samples)
Joining, by = "ntpos"
Joining, by = "MCoVNumber"
pa_tallies<-samples_spike_presence_absence %>% group_by(mutation, COLLECTION_DT) %>% summarise(n_consensus=sum(consensus_change), n_minor=sum(minor_change)) %>% pivot_longer(cols=3:4, names_to="type", values_to="cases")
`summarise()` has grouped output by 'mutation'. You can override using the `.groups` argument.
spike_interesting<-pa_tallies %>% filter(mutation %in% c("S NTD: L18F", "S NTD: T20N","S RBD: N439K","S RBD: L452R","S RBD: E484K", "S RBD: E484Q","S RBD: S494P", "S RBD: N501Y", "S RBD: A520S"))
spike_interesting$mutation<-factor(spike_interesting$mutation, levels=c("S NTD: L18F", "S NTD: T20N","S RBD: N439K","S RBD: L452R","S RBD: E484K", "S RBD: E484Q","S RBD: S494P", "S RBD: N501Y", "S RBD: A520S"))
high_spike<- spike_interesting %>% filter(mutation %in% c("S RBD: L452R","S RBD: N501Y")) %>% ggplot(aes(x=COLLECTION_DT, y=cases, color=type)) + geom_line() + facet_wrap(mutation~., scales="free_y") + scale_x_date(minor_breaks = "1 month")+ theme_bw() + scale_color_manual(values=c("gray","#F21A00")) + theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.position = "none", legend.text =element_text(size=12), legend.title=element_text(size=14))+ xlab("Collection Date") + ylab("No. samples")
lower_spike<- spike_interesting %>% filter(!mutation %in% c("S RBD: L452R","S RBD: N501Y")) %>% ggplot(aes(x=COLLECTION_DT, y=cases, color=type)) + geom_line() + facet_wrap(~mutation, scales="free_y") + scale_x_date(minor_breaks = "1 month")+theme_bw() + scale_color_manual(values=c("gray","#F21A00")) + theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.position = "none", legend.text =element_text(size=12), legend.title=element_text(size=14))+ xlab("Collection Date") + ylab("No. samples")
spike_plots<-plot_grid(high_spike, lower_spike, ncol=2)
high_nonspike<-pa_tallies %>% filter(mutation %in% c("M: I82T", "N: D377Y", "N: S235F", "ORF3a: S26L", "ORF8: R52I")) %>% ggplot(aes(x=COLLECTION_DT, y=cases, color=type)) + geom_line() + facet_wrap(~mutation,scales="free_y") + scale_x_date(minor_breaks = "1 month")+theme_bw() + scale_color_manual(values=c("gray","#F21A00"), labels=c("Consensus","Minor")) + theme_bw() + theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.position=c(0.8,0.2), legend.text =element_text(size=12), legend.title=element_blank())+ xlab("Collection Date") + ylab("No. samples")
chronologies<-plot_grid(spike_plots, high_nonspike, nrow=2, rel_heights=c(1,0.5), labels="auto")
#FIGURE 5A/B
chronologies

# B.1.1.7 and B.1.617.2 lineage-defining mutations in minority
calculate_test<-function(sample_sites_table, snp_table, minor_lineages_of_interest, maf_at_sites, depth_at_sites, min_reads, prop_sites, full_sample_list) {
#empty data frame of sample name, nucleotide positions of interest, and major and minor alleles
subs<-data.frame(MCoVNumber=as.character(), minor_lineage_or_mutation=as.character(), ntpos=as.numeric(), minorfreq=as.numeric(), totalcount=as.numeric())
#calculate number of mutations needed to count minor lineage as present
mutation_number_thresholds<-snp_table %>% group_by(lineage) %>% summarise(threshold_minor_mutations=n()*prop_sites)
#empty data frame of all sample/lineage combinations
full_combo<-expand.grid(MCoVNumber=pull(full_sample_list, MCoVNumber), minor_lineage_or_mutation=lineages_of_interest) %>% arrange(MCoVNumber)
#keep only positions with minor variants present at right MAF and depth
depth_freq<-filter(sample_sites_table, minorfreq>=maf_at_sites) %>% filter(totalcount>depth_at_sites) %>% filter(minorfreq*totalcount>=min_reads)
#check for correct allele at minor variant site for each lineage
for (lin in lineages_of_interest) {
print(lin)
snps<-filter(snp_table, lineage==lin)
temp<-left_join(depth_freq, snps, by=c("ntpos"="position")) %>% filter(!is.na(lineage)) %>% filter(minor==allele) %>% select(MCoVNumber,lineage,ntpos,minorfreq,totalcount) %>% rename(c("minor_lineage_or_mutation"="lineage"))
subs<-rbind(subs,temp)
}
write.csv(subs, "minor_subs_temp_workinglist.csv", row.names=FALSE)
print("Minor variant depth/freq written to minor_subs_temp.csv")
#count number of mutations of each variant present
minor_sites_tallies<-subs %>% group_by(MCoVNumber,minor_lineage_or_mutation) %>% summarise(number_minor_mutations=n()) %>% left_join(mutation_number_thresholds, by=c("minor_lineage_or_mutation"="lineage"))
#calculate whether number of mutations in the sample exceeds threshold for lineage being considered present in the minor fraction
minor_sites_tallies %>% filter(number_minor_mutations>=threshold_minor_mutations) %>% select(MCoVNumber, minor_lineage_or_mutation) %>% mutate(minor_present=1) %>% right_join(full_combo) -> tallies
final_tallies<-left_join(full_combo, tallies)
final_tallies[is.na(final_tallies)]<-0
print("List finalized")
return(final_tallies)
}
snp_table<-read.csv("lineage_and_single_mutations.csv") %>% mutate(position=as.numeric(position))
lineages_of_interest<-c("B.1.1.7", "B.1.617.2")
new_table <-calculate_test(sample_sites_table=variant_sites_threshold, snp_table=snp_table, minor_lineages_of_interest=lineages_of_interest, maf_at_sites=0.03, depth_at_sites=100, min_reads=10, prop_sites=0.6, full_sample_list=sample_list)
[1] "B.1.1.7"
[1] "B.1.617.2"
[1] "Minor variant depth/freq written to minor_subs_temp.csv"
`summarise()` has grouped output by 'MCoVNumber'. You can override using the `.groups` argument.
Joining, by = c("MCoVNumber", "minor_lineage_or_mutation")
Joining, by = c("MCoVNumber", "minor_lineage_or_mutation")
[1] "List finalized"
minor_lineages<-new_table %>% filter(MCoVNumber %in% working_samples$MCoVNumber) %>% left_join(working_samples)
Joining, by = "MCoVNumber"
minor_lineages %>% filter(minor_present==1) %>% arrange(COLLECTION_DT)
NA
#were there other B.1.1.7 samples in the same sequencing run?
minor_lineages %>% filter(minor_lineage_or_mutation=="B.1.1.7") %>% filter(minor_present==1) %>% group_by(run_id_final) %>% summarise(n=n()) %>% pull(run_id_final) -> r
mcov_samples_with_info %>% filter(pango_lineage=="B.1.1.7") %>% group_by(run_id_final) %>% summarise(n=n()) %>% pull(run_id_final) -> rc
setdiff(r,rc) #run 32 has no consensus B.1.7 but one minor (from December)
[1] "Run_32"
#were any of these minor-B.1.1.7 samples in the resequencing dataset?
samples_to_recheck <-minor_lineages %>% filter(minor_lineage_or_mutation=="B.1.1.7") %>% filter(minor_present==1) %>% filter(MCoVNumber %in% all_replicates_table_filt$MCoVNumber) %>% pull(MCoVNumber)
minors_table %>% filter(MCoVNumber %in% samples_to_recheck) %>% filter(ntpos %in% filter(snp_table, lineage=="B.1.1.7")$position) %>% left_join(filter(snp_table, lineage=="B.1.1.7"), by=c("ntpos"="position")) %>% mutate(b117_allele=if_else(minor.original==allele,1,0)) %>% filter(b117_allele==1) %>% group_by(MCoVNumber) %>% summarise(n_in_original=n(), n_recovered=sum(recovered_minor)) %>% arrange(n_recovered) %>% mutate(minor_fraction_reproduced=if_else(n_recovered>=11.4, 1,0, missing=NA_real_))
b117_minor_dates<-minor_lineages %>% filter(minor_lineage_or_mutation=="B.1.1.7") %>% filter(minor_present==1) %>% ggplot(aes(x=COLLECTION_DT)) + geom_bar(color="black") + scale_x_date(minor_breaks = "1 month") + theme_bw() + geom_vline(xintercept=as.numeric(as.Date("2021-01-12")), linetype="dashed", color="gray") +
annotate(geom = "text", x =as.Date("2021-01-12"), y=1.5, label = "Alpha wave", vjust=0, angle = 90) +
geom_vline(xintercept=as.numeric(as.Date("2021-06-15")), linetype="dashed", color="gray") +
annotate(geom = "text", x =as.Date("2021-06-15"), y=1.5, label = "Delta wave", vjust=0, angle = 90) +
theme(axis.text.x=element_text(size=12), axis.text.y=element_text(size=12), axis.title.x=element_text(size=14),axis.title.y=element_text(size=14), legend.position = c(0.8,0.7), legend.text =element_text(size=12), legend.title=element_text(size=14)) + xlab("Collection date") + ylab("No. samples")
#FIGURE 5
plot_grid(chronologies, b117_minor_dates, nrow=2, labels=c(NA,"c"), rel_heights = c(3,1))
Warning: Removed 1 rows containing missing values (geom_text).

inclusion_table<-mcov_samples_with_info %>% filter(COLLECTION_DT>="2020-12-01" & COLLECTION_DT<="2021-07-31") %>% select(MCoVNumber) %>% mutate(high_coverage_included=if_else(MCoVNumber %in% working_samples$MCoVNumber, 1,0), clinical_included_has_CT=if_else(MCoVNumber %in% filter(pds,is.na(CT))$MCoVNumber,1,0))
write.csv(inclusion_table, "inclusion_table.csv")
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KGdnZ2VuZXMpCmxpYnJhcnkobmxtZSkKbGlicmFyeShyYW5kb21Gb3Jlc3QpCmxpYnJhcnkocFJPQykKbGlicmFyeShnbG1uZXQpCmBgYAojUmVqb2luIHNwbGl0IGZpbGVzIGNvbnRhaW5pbmcgdmFyaWFudCBpbmZvCgpgYGB7cn0KCnN5c3RlbTIoImNhdCIsIGFyZ3MgPSAiLi92YXJpYW50X2xpc3RzL2FsbF9jaGFuZ2VzKiIsIHN0ZG91dCA9ICJhbGxfY29uc2Vuc3VzX21pbm9yaXR5X2NoYW5nZXMuY3N2IikKc3lzdGVtMigiY2F0IiwgYXJncyA9ICIuL3ZhcmlhbnRfbGlzdHMvbWlub3JfY2hhbmdlcyoiLCBzdGRvdXQgPSAidmFyaWFudF9zaXRlc19hbGwuY3N2IikKc3lzdGVtMigiY2F0IiwgYXJncyA9ICIuL3ZhcmlhbnRfbGlzdHMvcmVwbGljYXRlcyoiLCBzdGRvdXQgPSAicmVwbGljYXRlZF9zYW1wbGVzLmNzdiIpCgpgYGAKCgojIEluZm9ybWF0aW9uIGFib3V0IHNhbXBsZSBjb2xsZWN0aW9uLCBxdWFsaXR5LCBhbmQgc2VxdWVuY2luZyBydW4KIyMgQ29ubmVjdGluZyBzYW1wbGVzIGFuZCBtZXRhZGF0YQoKYGBge3J9CiNzYW1wbGVzIHJlY2VpdmVkIGZyb20gSG91c3RvbiwgcHJvY2Vzc2VkIHRocm91Z2ggdGltbyBwaXBlbGluZSBhbmQgYXNzaWduZWQgUGFuZ28gbGluZWFnZQphbGxfc2FtcGxlc190aW1vX3Byb2Nlc3NlZDwtcmVhZC5jc3YoImZ1bGxfbGluZWFnZV9yZXBvcnQudHN2IikgCgptY292X3NhbXBsZXMgPC0gYWxsX3NhbXBsZXNfdGltb19wcm9jZXNzZWQgJT4lIGZpbHRlcihzdGFydHNXaXRoKHRheG9uLCAiTUNvViIpKSAlPiUgbXV0YXRlKE1Db1ZOdW1iZXI9cmVnbWF0Y2hlcyh0YXhvbiwgcmVnZXhwcigiTUNvVi5bMC05XSsiLCB0YXhvbikpICU+JSBzdHJfcmVtb3ZlKCItIikgJT4lIHN0cl9yZW1vdmUoIl8iKSkgJT4lIHNlbGVjdChNQ29WTnVtYmVyLCBwYW5nb19saW5lYWdlPWxpbmVhZ2UpIAoKI2EgZmV3IHNhbXBsZXMgZG9uJ3QgaGF2ZSBuYW1lcyBmb3JtYXR0ZWQgTUNvViMjIywgcmVzdWx0aW5nIGluIGlkZW50aWNhbCBNQ29WIGlkcy4gRmlsdGVyIHRoZXNlIG91dCByYXRoZXIgdGhhbiByZW5hbWluZyBtYW51YWxseQpkdXBsaWNhdGVkX21jb3ZfbnVtYmVycyA8LSBtY292X3NhbXBsZXMgJT4lIGZpbHRlcihkdXBsaWNhdGVkKE1Db1ZOdW1iZXIpPT1UUlVFKSAlPiUgcHVsbChNQ29WTnVtYmVyKQptY292X3NhbXBsZXMgPC0gbWNvdl9zYW1wbGVzICU+JSBmaWx0ZXIoIShNQ29WTnVtYmVyICVpbiUgZHVwbGljYXRlZF9tY292X251bWJlcnMpKQoKI3NhbXBsZSBjb2xsZWN0aW9uIGRhdGVzLCBydW4gSURzLCBhbmQgSG91c3RvbiBjYWxsIG9uIHF1YWxpdHkgKCdsb3cgcXVhbGl0eScgbWVhbnMgNSUgb3IgbW9yZSBOcykKZGF0ZXNfYW5kX3J1bnM8LXJlYWQuY3N2KCI0X21jb3Zfc3RyYWluX3ZhcmlhbnRfbWFwX2NvdmlkX3BhbmdvbGluX2RiX2lucHV0X3J1bl82NS5jc3YiKSAlPiUgc2VwYXJhdGUoQ09MTEVDVElPTl9EVCwgaW50bz1jKCJDT0xMRUNUSU9OX0RUIiwidGltZSIpLCBzZXA9IiAiKSAlPiUgc2VsZWN0KE1Db1ZOdW1iZXIsIENPTExFQ1RJT05fRFQsIHF1YWxpdHksIHJ1bl9pZF9maW5hbCkgJT4lIG11dGF0ZShDT0xMRUNUSU9OX0RUPWFzLkRhdGUoQ09MTEVDVElPTl9EVCwgIiVtLyVkLyV5IiksIE1Db1ZOdW1iZXI9c3RyX3JlbW92ZShNQ29WTnVtYmVyLCItIikpCgojcVBDUiBpbnN0cnVtZW50IGFuZCBDdCB2YWx1ZSBvYnRhaW5lZCBpbiBIb3VzdG9uCiNBcHRpbWEgaW5zdHJ1bWVudCBjYWxjdWxhdGVzIHJlbGF0aXZlIGxpZ2h0IHVuaXRzLCBub3QgQ1QgLS0gYWRqdXN0IGNvbHVtbnMgYWNjb3JkaW5nbHkKY3RfZGF0YTwtcmVhZC5jc3YoImN0X2luc3RydW1lbnRfZGF0YV91cGRhdGUuY3N2IikgJT4lIG11dGF0ZShNQ29WTnVtYmVyPXN0cl9yZW1vdmUoTUNvVk51bWJlciwiLSIpKSAlPiUgc2VsZWN0KE1Db1ZOdW1iZXIsIElOU1RSVU1FTlQsIENUPUNUX1JFU1VMVCkgJT4lIG11dGF0ZShDVD1hcy5udW1lcmljKENUKSkgJT4lIG11dGF0ZShSTFU9aWZfZWxzZShJTlNUUlVNRU5UPT0iQVBUSU1BIiwgQ1QsIE5BX3JlYWxfKSkgJT4lIG11dGF0ZShDVD1pZl9lbHNlKGlzLm5hKFJMVSksIENULCBOQV9yZWFsXykpICU+JSBtdXRhdGUoQ1Q9YXMubnVtZXJpYyhDVCksIFJMVT1hcy5udW1lcmljKFJMVSkpCgojcGVyY2VudGFnZSBvZiBzaXRlcyB3aXRoIGF0IGxlYXN0IDEwMHggY292ZXJhZ2UgaW4gZWFjaCBzYW1wbGUKY292ZXJhZ2VfMTAweDwtcmVhZC5jc3YoImFsbF9zYW1wbGVzX2NvdmVyYWdlXzEwMHhfcmV2aXNlZC5jc3YiKSU+JSBzZWxlY3QoTUNvVk51bWJlcj1zYW1wbGVuYW1lLCBmcmFjdGlvbl8xMDB4X2NvdmVyYWdlKQoKc2FtcGxlX2luZm88LWxlZnRfam9pbihkYXRlc19hbmRfcnVucywgY3RfZGF0YSkgJT4lIGxlZnRfam9pbihjb3ZlcmFnZV8xMDB4KQoKbWNvdl9zYW1wbGVzX3dpdGhfaW5mbzwtbGVmdF9qb2luKG1jb3Zfc2FtcGxlcywgc2FtcGxlX2luZm8pICU+JSBmaWx0ZXIoIWlzLm5hKENPTExFQ1RJT05fRFQpKSAjc2FtcGxlcyB3aXRob3V0IGRhdGVzIGluIGRhdGFiYXNlIGNvbmZpcm1lZCBub3QgdG8gaGF2ZSBkYXRlIGluZm87IGV4Y2x1ZGUKYGBgCgojIyBGaWx0ZXJpbmcgc2FtcGxlcwpTZXZlcmFsIHN0ZXBzIG9mIFFDIGZpbHRlcmluZyB0byBnZXQgdG8gZmluYWwgd29ya2luZ19zYW1wbGVzIGxpc3Qgb2YgaW5jbHVkZWQgc2FtcGxlcwoKYGBge3J9CiNLZWVwIG9ubHkgc2FtcGxlcyBmcm9tIERlYyAyMDIwIHRocm91Z2ggSnVseSAyMDIxIGFuZCB3aXRoIDEwMHggY292ZXJhZ2Ugb3ZlciA5NSUgb2YgZ2Vub21lLiBFeGNsdWRlIHNhbXBsZXMgZnJvbSBydW5zIDIwIGFuZCAyMSBvciBjbGFzc2lmaWVkIGFzIGxvdyBxdWFsaXR5Cndvcmtpbmdfc2FtcGxlcyA8LSBtY292X3NhbXBsZXNfd2l0aF9pbmZvICU+JSBmaWx0ZXIoQ09MTEVDVElPTl9EVD4iMjAyMC0xMS0zMCIgJiBDT0xMRUNUSU9OX0RUPCIyMDIxLTA4LTAxIikgJT4lIGZpbHRlcihmcmFjdGlvbl8xMDB4X2NvdmVyYWdlPj0wLjk1KSAlPiUgZmlsdGVyKHF1YWxpdHkhPSJMUSIpICU+JSBmaWx0ZXIoIShydW5faWRfZmluYWwgJWluJSBjKCJSdW5fMjAiLCJSdW5fMjEiKSkpICU+JSBmaWx0ZXIocGFuZ29fbGluZWFnZSE9Ik5vbmUiKQoKI0lkZW50aWZ5IHNhbXBsZXMgY29taW5nIGZyb20gdGhlIHNhbWUgcGF0aWVudDsga2VlcCBvbmx5IHRoZSBlYXJsaWVzdCBzYW1wbGUgZnJvbSBwYXRpZW50CiNpZGVudGlmeSBzYW1wbGVzIGNvbWluZyBmcm9tIHRoZSBzYW1lIHBhdGllbnQKcF9saXN0PC1yZWFkLmNzdigicGF0aWVudElEX21jb3YuY3N2IikgJT4lIG11dGF0ZShNQ29WTnVtYmVyPXN0cl9yZW1vdmUoTUNvVk51bWJlciwgIi0iKSkgJT4lIHNlbGVjdChNQ29WTnVtYmVyLCBQYXRpZW50SUQpCgptdWx0aV9zYW1wbGVfcGF0aWVudHMgPC0gd29ya2luZ19zYW1wbGVzICU+JSBsZWZ0X2pvaW4ocF9saXN0KSAlPiUgZmlsdGVyKGR1cGxpY2F0ZWQoUGF0aWVudElEKSkgJT4lIHB1bGwoUGF0aWVudElEKSAlPiUgdW5pcXVlKCkgCnNhbXBsZXNfdG9fZGVkdXA8LXBfbGlzdCAlPiUgZmlsdGVyKFBhdGllbnRJRCAlaW4lIG11bHRpX3NhbXBsZV9wYXRpZW50cykgJT4lIHB1bGwoTUNvVk51bWJlcikKCmxpc3RfdG9fZGVkdXA8LXdvcmtpbmdfc2FtcGxlcyAlPiUgZmlsdGVyKE1Db1ZOdW1iZXIgJWluJSBzYW1wbGVzX3RvX2RlZHVwKSAlPiUgbGVmdF9qb2luKHBfbGlzdCkKCiNsaXN0IHRvIGluY2x1ZGUgaW5jbHVkaW5nIHRoZSByYW5kb21seSBjaG9zZW4gb25lcyBmcm9tIHNhbWUtZGF5IHNhbXBsZXMgaXMgc2F2ZWQ6CmRlZHVwX211bHRpPC1yZWFkLmNzdigiZGVkdXBfZWFybHkuY3N2IikgJT4lIHB1bGwoeCkKCmRyb3BfbXVsdGk8LXNldGRpZmYoc2FtcGxlc190b19kZWR1cCwgZGVkdXBfbXVsdGkpCndvcmtpbmdfc2FtcGxlczwtd29ya2luZ19zYW1wbGVzICU+JSBmaWx0ZXIoIShNQ29WTnVtYmVyICVpbiUgZHJvcF9tdWx0aSkpIAoKI3J1biBjb25zZW5zdXMgc2VxdWVuY2VzIHRocm91Z2ggTmV4dGNsYWRlIFFDOyBleGNsdWRlIHNhbXBsZXMgd2hlcmUgY29uc2Vuc3VzIHNlcXVlbmNlIHdhcyBzY29yZWQgYXMgImJhZCIKYmFkX3NhbXBsZXM8LXJlYWQuY3N2KCJob3VzdG9uX25leHRjbGFkZS50c3YiLCBzZXA9J1x0JykgJT4lIGZpbHRlcihzdGFydHNXaXRoKHNlcU5hbWUsICJNQ29WIikpICU+JSBtdXRhdGUoTUNvVk51bWJlcj1yZWdtYXRjaGVzKHNlcU5hbWUsIHJlZ2V4cHIoIk1Db1YuWzAtOV0rIiwgc2VxTmFtZSkpICU+JSBzdHJfcmVtb3ZlKCItIikgJT4lIHN0cl9yZW1vdmUoIl8iKSkgJT4lIGZpbHRlcihxYy5vdmVyYWxsU3RhdHVzPT0iYmFkIiB8IHFjLm92ZXJhbGxTdGF0dXM9PSIiKSAlPiUgcHVsbChNQ29WTnVtYmVyKQoKd29ya2luZ19zYW1wbGVzPC13b3JraW5nX3NhbXBsZXMgJT4lIGZpbHRlcighTUNvVk51bWJlciAlaW4lIGJhZF9zYW1wbGVzKQpgYGAKCmBgYHtyfQojbHVtcCBsaW5lYWdlcyByZXByZXNlbnRlZCBieSBsZXNzIHRoYW4gMjAgc2FtcGxlcyBpbnRvIGFuIE90aGVyIGNhdGVnb3J5Cndvcmtpbmdfc2FtcGxlcyAlPiUgZ3JvdXBfYnkocGFuZ29fbGluZWFnZSkgJT4lIHN1bW1hcmlzZShuPW4oKSkgJT4lIGZpbHRlcihuPj0yMCkgJT4lIHB1bGwocGFuZ29fbGluZWFnZSkgLT4gbGluZWFnZXNfb3Zlcl8yMAp3b3JraW5nX3NhbXBsZXMkcGFuZ29fbGluZWFnZV9jPC1pZl9lbHNlKHdvcmtpbmdfc2FtcGxlcyRwYW5nb19saW5lYWdlICVpbiUgbGluZWFnZXNfb3Zlcl8yMCwgd29ya2luZ19zYW1wbGVzJHBhbmdvX2xpbmVhZ2UsICJPdGhlciIpCiNiaW4gbGluZWFnZXMgYnkgY29sbGVjdGlvbiBtb250aAp3b3JraW5nX3NhbXBsZXMgPC0gd29ya2luZ19zYW1wbGVzICU+JSBtdXRhdGUoY29sbGVjdGlvbl9tb250aD1mb3JtYXQoYXMuRGF0ZShDT0xMRUNUSU9OX0RUKSwgIiVZLSVtIikpCiNzYW1wbGVzIGJ5IGNvbGxlY3Rpb24gbW9udGggYW5kIHNlcXVlbmNpbmcgcnVuCnRhYmxlKHdvcmtpbmdfc2FtcGxlcyRydW5faWRfZmluYWwsIHdvcmtpbmdfc2FtcGxlcyRjb2xsZWN0aW9uX21vbnRoKQpgYGAKCgpgYGB7cn0KI2hvdyBkb2VzIGZpbHRlcmluZyBhZmZlY3QgdGhlIGRpc3RyaWJ1dGlvbiBvZiBDVCB2YWx1ZXM/Cm1jb3Zfc2FtcGxlc193aXRoX2luZm8gJT4lIHB1bGwoQ1QpICU+JSBtZWRpYW4obmEucm09VFJVRSkgICNiZWZvcmUgZmlsdGVyaW5nCndvcmtpbmdfc2FtcGxlcyAlPiUgcHVsbChDVCkgJT4lIG1lZGlhbihuYS5ybT1UUlVFKSAjYWZ0ZXIgZmlsdGVyaW5nCmBgYAoKYGBge3J9CiNkaXN0cmlidXRpb25zIG9mIENUIHZhbHVlcyBiZWZvcmUgYW5kIGFmdGVyIGZpbHRlcmluZwpjdF9hbGxzYW1wbGVzPC1tY292X3NhbXBsZXNfd2l0aF9pbmZvICU+JSBmaWx0ZXIoSU5TVFJVTUVOVCAlaW4lIGMoIkFMSU5JVFkiLCJQQU5USEVSIikpICU+JSBnZ3Bsb3QoYWVzKHg9Q1QpKSArIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTIpICsgZmFjZXRfd3JhcCh+SU5TVFJVTUVOVCkgKyB0aGVtZV9idygpICsgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQoc2l6ZT0xNCksYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dChzaXplPTE0KSwgbGVnZW5kLnBvc2l0aW9uID0gYygwLjgsMC43KSwgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTYpLCBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTQpKSArIGxhYnMoY2FwdGlvbj0iQmVmb3JlIGV4Y2x1c2lvbiBjcml0ZXJpYSIpCgpjdF93b3JraW5nc2FtcGxlczwtd29ya2luZ19zYW1wbGVzICU+JSBmaWx0ZXIoSU5TVFJVTUVOVCAlaW4lIGMoIkFMSU5JVFkiLCJQQU5USEVSIikpICU+JSBnZ3Bsb3QoYWVzKHg9Q1QpKSArIGdlb21faGlzdG9ncmFtKCkgKyBmYWNldF93cmFwKH5JTlNUUlVNRU5UKSArIHRoZW1lX2J3KCkgKyB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTEyKSwgYXhpcy50aXRsZS54PWVsZW1lbnRfdGV4dChzaXplPTE0KSxheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHNpemU9MTQpLCBsZWdlbmQucG9zaXRpb24gPSBjKDAuOCwwLjcpLCBsZWdlbmQudGV4dCA9ZWxlbWVudF90ZXh0KHNpemU9MTYpLCBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTQpKSArIGxhYnMoY2FwdGlvbj0iQWZ0ZXIgZXhjbHVzaW9uIGNyaXRlcmlhIikKCmN0X2hpc3RvZ3JhbXM8LXBsb3RfZ3JpZChjdF9hbGxzYW1wbGVzLCBjdF93b3JraW5nc2FtcGxlcywgbnJvdz0yLCBsYWJlbHM9TkEpCmBgYAoKYGBge3J9CiNlZmZlY3Qgb2YgYnJlYWR0aC9kZXB0aCBvZiBjb3ZlcmFnZSBvbiBtaW5vciB2YXJpYW50IGRldGVjdGlvbgptY292X3NhbXBsZXNfbGlzdDwtbWNvdl9zYW1wbGVzX3dpdGhfaW5mbyAlPiUgc2VsZWN0KE1Db1ZOdW1iZXIsIGZyYWN0aW9uXzEwMHhfY292ZXJhZ2UpIApuX3Zhcl9jb3ZlcmFnZTwtcmVhZC5jc3YoInZhcmlhbnRfc2l0ZXNfdGhyZXNob2xkLmNzdiIpICU+JSBncm91cF9ieShNQ29WTnVtYmVyKSAlPiUgc3VtbWFyaXNlKG5fdmFyPW4oKSkgJT4lIHJpZ2h0X2pvaW4obWNvdl9zYW1wbGVzX2xpc3QpICU+JSBtdXRhdGUobl92YXI9cmVwbGFjZV9uYShuX3ZhciwwKSxjb3ZlcmFnZV9ncm91cD1jdXQoZnJhY3Rpb25fMTAweF9jb3ZlcmFnZSwgYnJlYWtzPSBjKDAsMC42NSwwLjk1LDEpLCByaWdodD1GQUxTRSkpICU+JSBnZ3Bsb3QoYWVzKHg9Y292ZXJhZ2VfZ3JvdXAsIHk9bl92YXIpKSArIGdlb21fYm94cGxvdChvdXRsaWVyLmFscGhhID0gMC41LCBvdXRsaWVyLnNpemU9MC41KSArIHhsYWIoIkZyYWN0aW9uIG9mIGdlbm9tZSB3aXRoIGF0IGxlYXN0IDEwMHggY292ZXJhZ2UiKSArIHlsYWIoIk51bWJlciBvZiBtaW5vciB2YXJpYW50cyBkZXRlY3RlZCIpICsgdGhlbWVfYncoKSArIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTEyKSwgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRpdGxlLng9ZWxlbWVudF90ZXh0KHNpemU9MTQpLGF4aXMudGl0bGUueT1lbGVtZW50X3RleHQoc2l6ZT0xNCksIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44LDAuNyksIGxlZ2VuZC50ZXh0ID1lbGVtZW50X3RleHQoc2l6ZT0xNiksIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xNCkpIApgYGAKCmBgYHtyfQojRklHVVJFIFMxCnBsb3RfZ3JpZChuX3Zhcl9jb3ZlcmFnZSwgY3RfaGlzdG9ncmFtcywgbGFiZWxzPSJhdXRvIiwgbmNvbD0yKQpgYGAKCiMjIEdlbmUgYW5kIHByaW1lciBwb3NpdGlvbnMKCmBgYHtyfQpyZWFkLmNzdigibkNvVi0yMDE5LmFydGljX3YzLnByaW1lci50eHQiLCBzZXA9Ilx0IiwgaGVhZGVyPUZBTFNFKSAlPiUgc2VsZWN0KHN0YXJ0PVYyLCBlbmQ9VjMpIC0+IHByaW1lcnMKcHJpbWVyX3Bvc2l0aW9uczwtYXMubnVtZXJpYygpCmZvciAoaSBpbiAxOm5yb3cocHJpbWVycykpewogIHByaW1lcl9wb3NpdGlvbnM8LWMocHJpbWVyX3Bvc2l0aW9ucywgcHJpbWVyc1tpLF0kc3RhcnQ6cHJpbWVyc1tpLF0kZW5kKQp9CgojZ2VuZSBwb3NpdGlvbnMKZ2VuZXM8LXJlYWQuY3N2KCJudHBvc19nZW5lX3VwZGF0ZS5jc3YiKSAlPiUgbXV0YXRlKGdlbmVfaWQ9YXMuZmFjdG9yKGdlbmVfaWQpKQpnZW5lcyAlPiUgYXJyYW5nZShudHBvcykgJT4lIHB1bGwoZ2VuZV9pZCkgJT4lIHVuaXF1ZSgpIC0+IGdlbmVfbmFtZXMKZ2VuZXMkZ2VuZV9pZCA8LSBmYWN0b3IoZ2VuZXMkZ2VuZV9pZCwgbGV2ZWxzPWdlbmVfbmFtZXMpCmdlbmVzICU+JSBncm91cF9ieShnZW5lX2lkKSAlPiUgc3VtbWFyaXNlKGdlbmVfbGVuZ3RoPW4oKSkgLT4gZ2VuZV9sZW5ndGhzCgoKYGBgCgojIENvbnNlbnN1cyBsaW5lYWdlIGNoYW5nZXMgb3ZlciB0aW1lCgpgYGB7cn0KIyBnZXQgbnVtYmVycyBvZiBlYWNoIGxpbmVhZ2UgYW5kIHRvdGFscyBwZXIgZGF5CmxpbmVhZ2VzX2RhdGVzPC13b3JraW5nX3NhbXBsZXMgJT4lIGdyb3VwX2J5KENPTExFQ1RJT05fRFQsIHBhbmdvX2xpbmVhZ2UpICU+JSBzdW1tYXJpc2Uobl9jYXNlcz1uKCkpICU+JSBwaXZvdF93aWRlcihpZF9jb2xzPUNPTExFQ1RJT05fRFQsIG5hbWVzX2Zyb209cGFuZ29fbGluZWFnZSwgdmFsdWVzX2Zyb209bl9jYXNlcykKdG90YWxfY2FzZXM8LWxpbmVhZ2VzX2RhdGVzICU+JSB1bmdyb3VwICU+JSBzZWxlY3QoIUNPTExFQ1RJT05fRFQpICU+JSByb3dTdW1zKG5hLnJtPVRSVUUpCmxpbmVhZ2VzX2RhdGVzJHRvdGFsX2Nhc2VzPC10b3RhbF9jYXNlcwoKY29uc2Vuc3VzX2xpbmVhZ2VfYnlfZGF0ZTwtbGluZWFnZXNfZGF0ZXMgJT4lIHBpdm90X2xvbmdlcihjb2xzPS0xLCBuYW1lc190bz0ibGluZWFnZSIsIHZhbHVlc190bz0iY2FzZXMiKSAlPiUgbXV0YXRlKGNhc2VzPXJlcGxhY2VfbmEoY2FzZXMsMCkpCgojIGEgbGlzdCBvZiBkYWlseSBjYXNlIG51bWJlcnMKZGFpbHlfY2FzZXM8LWNvbnNlbnN1c19saW5lYWdlX2J5X2RhdGUgJT4lIGZpbHRlcihsaW5lYWdlPT0idG90YWxfY2FzZXMiKSAlPiUgc2VsZWN0KENPTExFQ1RJT05fRFQsIGNhc2VzKQoKI0ZJR1VSRSAxCmNvbnNlbnN1c19saW5lYWdlX2J5X2RhdGUgJT4lIGZpbHRlcihsaW5lYWdlICVpbiUgYygidG90YWxfY2FzZXMiLCJCLjEuMiIsIkIuMS4xLjciLCJCLjEuNjE3LjIiKSkgJT4lIGdncGxvdChhZXMoeD1DT0xMRUNUSU9OX0RULCB5PWNhc2VzLCBjb2xvcj1saW5lYWdlKSkgKyBnZW9tX2xpbmUoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzAwMDAwMCIsICIjNDZBQ0M4IiwgIiNFNTg2MDEiLCAiI0I0MEYyMCIpLCAKICAgICAgICAgICAgICAgICAgICAgbGltaXRzPWMoInRvdGFsX2Nhc2VzIiwgIkIuMS4yIiwgIkIuMS4xLjciLCJCLjEuNjE3LjIiKSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIlRvdGFsIHNhbXBsZXMiLCJCLjEuMiIsIkIuMS4xLjciLCJCLjEuNjE3LjIiKSkgKyAgIHNjYWxlX3hfZGF0ZShtaW5vcl9icmVha3MgPSAiMSBtb250aCIpICsKICB0aGVtZV9idygpICsgeGxhYigiQ29sbGVjdGlvbiBEYXRlICgyMDIwLTIwMjEpIikgKyB5bGFiKCJOdW1iZXIgb2Ygc2FtcGxlcyIpICsgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQoc2l6ZT0xNCksYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dChzaXplPTE0KSwgbGVnZW5kLnBvc2l0aW9uID0gYygwLjgsMC43KSwgbGVnZW5kLnRleHQgPWVsZW1lbnRfdGV4dChzaXplPTEyKSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE0KSkgKyBsYWJzKGNvbG9yPU5VTEwpCmBgYAojIFRvdGFsIG1pbm9yIHZhcmlhbnQgcmljaG5lc3MKCmBgYHtyfQojZmlsZSBjb2xsZWN0aW5nIGFsbCBzaXRlcyBpbiBzYW1wbGVzIHRoYXQgaGF2ZSBtaW5vciB2YXJpYW50cyBkZXRlY3RlZCBhdCBhbnkgZnJlcXVlbmN5LCBhdCBzaXRlcyB3aXRoIGF0IGxlYXN0IDEwMCByZWFkcwphbGxfdmFyaWFudF9zaXRlczwtcmVhZC5jc3YoInZhcmlhbnRfc2l0ZXNfYWxsLmNzdiIpCnplcm9fdmFyaWFudF9zYW1wbGVzPC1yZWFkLmNzdigiemVyb3Zhci5jc3YiKSAlPiUgc2VsZWN0KG5hbWU9eCkgJT4lIG11dGF0ZShudHBvcz1OQSwgbWFqb3I9TkEsIG1ham9yZnJlcT1OQSwgbWlub3I9TkEsIG1pbm9yZnJlcT1OQSwgdG90YWxjb3VudD1OQSwgYmlub2NoZWNrPU5BLCBNQ29WTnVtYmVyPW5hbWUpCmFsbF92YXJpYW50X3NpdGVzPC1yYmluZChhbGxfdmFyaWFudF9zaXRlcywgemVyb192YXJpYW50X3NhbXBsZXMpICU+JSBzZWxlY3QoTUNvVk51bWJlciwgbnRwb3MsIG1ham9yLCBtaW5vciwgbWlub3JmcmVxLCB0b3RhbGNvdW50KQoKI2tlZXBpbmcgb25seSBzaXRlcyBtZWV0aW5nIG1pbm9yIHZhcmlhbnQgdGhyZXNob2xkIGNyaXRlcmlhCnZhcmlhbnRfc2l0ZXNfdGhyZXNob2xkPC1hbGxfdmFyaWFudF9zaXRlcyAlPiUgCiAgZmlsdGVyKG1pbm9yZnJlcT49MC4wMyAmIG1pbm9yZnJlcSp0b3RhbGNvdW50Pj0xMCkgJT4lIAogIGZpbHRlcihtYWpvciAlaW4lIGMoIkEiLCJUIiwiRyIsIkMiKSkgJT4lCiAgZmlsdGVyKG1pbm9yICVpbiUgYygiQSIsIlQiLCJHIiwiQyIpKSAlPiUKICBmaWx0ZXIoIShudHBvcyAlaW4lIHByaW1lcl9wb3NpdGlvbnMpKQoKc2FtcGxlX2xpc3Q8LXdvcmtpbmdfc2FtcGxlcyAlPiUgc2VsZWN0KE1Db1ZOdW1iZXIpICU+JSB1bmlxdWUoKQpjb3VudHM8LXZhcmlhbnRfc2l0ZXNfdGhyZXNob2xkICU+JSAgZ3JvdXBfYnkoTUNvVk51bWJlcikgJT4lIHN1bW1hcmlzZShuX3Zhcj1uKCkpCnZhcl9saXN0PC1sZWZ0X2pvaW4oc2FtcGxlX2xpc3QsIGNvdW50cykgJT4lIG11dGF0ZShuX3Zhcj1yZXBsYWNlX25hKG5fdmFyLCAwKSkKCnNhbXBsZXNfbl92YXI8LWxlZnRfam9pbih3b3JraW5nX3NhbXBsZXMsIHZhcl9saXN0KQoKbWVkaWFuKHNhbXBsZXNfbl92YXIkbl92YXIpCm1lZGlhbihmaWx0ZXIoc2FtcGxlc19uX3ZhciwgQ1Q8PTI1KSRuX3ZhcikKbnJvdyhmaWx0ZXIoc2FtcGxlc19uX3Zhciwgbl92YXI8MTApKSAvIG5yb3coc2FtcGxlc19uX3ZhcikKYGBgCgpgYGB7cn0KdmFyX2J5X2N0X2ZpZzwtc2FtcGxlc19uX3ZhciAlPiUgZmlsdGVyKElOU1RSVU1FTlQgJWluJSBjKCJBTElOSVRZIiwiUEFOVEhFUiIpKSAlPiUgZ2dwbG90KGFlcyh4PUNULCB5PW5fdmFyKSkgKyBnZW9tX3BvaW50KGFscGhhPTAuNSkgKyBmYWNldF9ncmlkKH5JTlNUUlVNRU5UKSsgdGhlbWVfYncoKSArIHN0YXRfc21vb3RoKGNvbG9yPSIjNDZBQ0M4IikgKyB0aGVtZV9idygpICsgeGxhYigiQ1QgdmFsdWUiKSArIHlsYWIoIk5vLiBtaW5vciB2YXJpYW50cyIpICsgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQoc2l6ZT0xNCksYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dChzaXplPTE0KSwgbGVnZW5kLnBvc2l0aW9uID0gYygwLjgsMC43KSwgbGVnZW5kLnRleHQgPWVsZW1lbnRfdGV4dChzaXplPTE2KSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE0KSwgc3RyaXAuYmFja2dyb3VuZCA9ZWxlbWVudF9yZWN0KGZpbGw9IiNFMkQyMDAiKSkgCgpzYW1wbGVzX25fdmFyX2ZpZzwtc2FtcGxlc19uX3ZhciAlPiUgZ2dwbG90KGFlcyh4PW5fdmFyKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD0xMCxmaWxsPSIjQjQwRjIwIikgKyB0aGVtZV9idygpICsgeGxhYigiTnVtYmVyIG9mIG1pbm9yIHZhcmlhbnQgc2l0ZXMgaW4gc2FtcGxlIikgKyB5bGFiKCJOdW1iZXIgb2Ygc2FtcGxlcyIpICsgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQoc2l6ZT0xNCksYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dChzaXplPTE0KSwgbGVnZW5kLnBvc2l0aW9uID0gYygwLjgsMC43KSwgbGVnZW5kLnRleHQgPWVsZW1lbnRfdGV4dChzaXplPTE2KSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE0KSkgIAoKCiNGSUdVUkUgMgogIGdnZHJhdyhzYW1wbGVzX25fdmFyX2ZpZyArIHRoZW1lX2hhbGZfb3BlbigxMikpICsKICAgIGRyYXdfcGxvdCh2YXJfYnlfY3RfZmlnLCAuMywgLjMsIC42LCAuNikgKwogICAgZHJhd19wbG90X2xhYmVsKAogICAgICBjKCJhIiwgImIiKSwKICAgICAgYygwLCAwLjQ1KSwKICAgICAgYygxLCAwLjk1KSwKICAgICAgc2l6ZSA9IDEyCiAgICApCmBgYAojIFJlcHJvZHVjaWJpbGl0eSBvZiBhZCBob2Mgc2FtcGxlcwoKYGBge3J9CmFsbF9yZXBsaWNhdGVzX3RhYmxlPC1yZWFkLmNzdigicmVwbGljYXRlZF9zYW1wbGVzLmNzdiIpCgojY2hlY2sgZm9yIHRvbyBtYW55IG1pc21hdGNoZXMgb24gdGhlIGNvbnNlbnN1cyBsZXZlbAphbGxfcmVwbGljYXRlc190YWJsZSAlPiUgCiAgbXV0YXRlKGhpZ2hfY29uZmlkZW5jZV9zaXRlPWlmX2Vsc2UobWFqb3Iub3JpZ2luYWwgJWluJSBjKCJBIiwiQyIsIlQiLCJHIikgJiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFqb3Iub3JpZ2luYWwgJWluJSBjKCJBIiwiQyIsIlQiLCJHIikgJiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG90YWxjb3VudC5vcmlnaW5hbD4xMDAgJiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG90YWxjb3VudC5yZXNlcT4xMDAgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYWpvcmZyZXEub3JpZ2luYWw+MC45ICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFqb3JmcmVxLnJlc2VxPjAuOSwxLDAsbWlzc2luZz0wKSkgJT4lIAogIG11dGF0ZShjb25zZW5zdXNfbWlzbWF0Y2g9aWZfZWxzZShoaWdoX2NvbmZpZGVuY2Vfc2l0ZT09MSAmIG1ham9yLm9yaWdpbmFsIT1tYWpvci5yZXNlcSwxLDApKSAlPiUgZ3JvdXBfYnkoTUNvVk51bWJlcikgJT4lIHN1bW1hcmlzZShjb25zZW5zdXNfbWlzbWF0Y2hlcz1zdW0oY29uc2Vuc3VzX21pc21hdGNoKSkgJT4lIGFycmFuZ2UoZGVzYyhjb25zZW5zdXNfbWlzbWF0Y2hlcykpICU+JSAKICBmaWx0ZXIoY29uc2Vuc3VzX21pc21hdGNoZXM+MikgJT4lIHB1bGwoTUNvVk51bWJlcikgLT4gY29uc2Vuc3VzX21pc21hdGNoX3NhbXBsZXMKCmFsbF9yZXBsaWNhdGVzX3RhYmxlX2ZpbHQ8LWFsbF9yZXBsaWNhdGVzX3RhYmxlICU+JSBmaWx0ZXIoIShNQ29WTnVtYmVyICVpbiUgY29uc2Vuc3VzX21pc21hdGNoX3NhbXBsZXMpKQoKCm1pbm9yc190YWJsZTwtYWxsX3JlcGxpY2F0ZXNfdGFibGVfZmlsdCAlPiUgZmlsdGVyKG1ham9yLm9yaWdpbmFsICVpbiUgYygiQSIsIkMiLCJUIiwiRyIpKSAlPiUgZmlsdGVyKG1pbm9yLm9yaWdpbmFsICVpbiUgYygiQSIsIkMiLCJUIiwiRyIpKSAlPiUKICBmaWx0ZXIodG90YWxjb3VudC5vcmlnaW5hbD4xMDAgJiBtaW5vcmZyZXEub3JpZ2luYWw+PTAuMDMgJiB0b3RhbGNvdW50Lm9yaWdpbmFsKm1pbm9yZnJlcS5vcmlnaW5hbD49MTAgJiB0b2xvd2VyKGJpbm9jaGVjay5vcmlnaW5hbCkhPSJmYWxzZSIpICU+JSBmaWx0ZXIoKCFudHBvcyAlaW4lIHByaW1lcl9wb3NpdGlvbnMpKQoKI251bWJlciBvZiBtaW5vciB2YXJpYW50cyBvcmlnaW5hbGx5IGFuZCBob3cgbWFueSBhcmUgcmVwcm9kdWNpYmxlCm1pbm9yc190YWJsZSAlPiUgbXV0YXRlKHJlY292ZXJlZF9taW5vcj1pZl9lbHNlKG1pbm9yLm9yaWdpbmFsPT1taW5vci5yZXNlcSwxLDAsbWlzc2luZz0wKSkgJT4lIGdyb3VwX2J5KE1Db1ZOdW1iZXIpICU+JSBzdW1tYXJpc2Uobl92YXJfb3JpZ2luYWw9bigpLCBuX3Zhcl9yZXByb2R1Y2libGU9c3VtKHJlY292ZXJlZF9taW5vcikpLT5zYW1wbGVzX25fdmFyX3JlcHJvZHVjaWJsZQoKcmVwcm9kX3NhbXBsZXM8LXNlbGVjdChhbGxfcmVwbGljYXRlc190YWJsZSwgTUNvVk51bWJlcikgJT4lIGZpbHRlcighZHVwbGljYXRlZChNQ29WTnVtYmVyKSkgJT4lICBmaWx0ZXIoIShNQ29WTnVtYmVyICVpbiUgY29uc2Vuc3VzX21pc21hdGNoX3NhbXBsZXMpKSAlPiUgbGVmdF9qb2luKHNhbXBsZXNfbl92YXJfcmVwcm9kdWNpYmxlKSAlPiUgbXV0YXRlKG5fdmFyX29yaWdpbmFsPXJlcGxhY2VfbmEobl92YXJfb3JpZ2luYWwsIDApLCBuX3Zhcl9yZXByb2R1Y2libGU9cmVwbGFjZV9uYShuX3Zhcl9yZXByb2R1Y2libGUsIDApKQoKcmVwcm9kX3NhbXBsZXMgJT4lIGZpbHRlcihuX3Zhcl9yZXByb2R1Y2libGU+PTMpICU+JSBwdWxsKE1Db1ZOdW1iZXIpIC0+IHNhbXBsZXNfM3JlcCAjc2FtcGxlcyB3aXRoIGF0IGxlYXN0IDMgcmVwcm9kdWNpYmxlIHZhcmlhbnRzLCBmb3IgY29tcGFyaW5nIGZyZXF1ZW5jaWVzIGxhdGVyCgojd2hhdCdzIHRoZSBtZWRpYW4gbnVtYmVyIG9mIHJlcHJvZHVjaWJsZSBtaW5vciB2YXJpYW50cz8KcmVwcm9kX3NhbXBsZXMgJT4lIHB1bGwobl92YXJfb3JpZ2luYWwpICU+JSBtZWRpYW4obmEucm09VFJVRSkKcmVwcm9kX3NhbXBsZXMgJT4lIHB1bGwobl92YXJfcmVwcm9kdWNpYmxlKSAlPiUgbWVkaWFuKG5hLnJtPVRSVUUpCmBgYAoKCmBgYHtyfQptaW5vcnNfdGFibGU8LW1pbm9yc190YWJsZSAlPiUgbXV0YXRlKHJlY292ZXJlZF9taW5vcj1pZl9lbHNlKG1pbm9yLm9yaWdpbmFsPT1taW5vci5yZXNlcSwxLDAsbWlzc2luZz0wKSkgCmxhYmVscyA8LSBjKGAwYCA9ICJOb24tcmVwcm9kdWNpYmxlIHNpdGUiLCBgMWAgPSAiUmVwcm9kdWNpYmxlIHNpdGUiKQpkZXB0aHNfcmVwPC1taW5vcnNfdGFibGUgJT4lIGdncGxvdChhZXMoeD10b3RhbGNvdW50Lm9yaWdpbmFsLCB5PW1pbm9yZnJlcS5vcmlnaW5hbCkpICsgZ2VvbV9wb2ludChhbHBoYT0wLjUpICsgCiAgZmFjZXRfZ3JpZChyZWNvdmVyZWRfbWlub3J+LiwgbGFiZWxsZXI9bGFiZWxsZXIocmVjb3ZlcmVkX21pbm9yID0gbGFiZWxzKSkgKyAKICB4bGFiKCJSZWFkIGRlcHRoIGF0IHNpdGUgaW4gZmlyc3QgcmVwbGljYXRlIikgKyB5bGFiKCJNQUYgYXQgc2l0ZSBpbiBmaXJzdCByZXBsaWNhdGUiKSArCiAgICAgICAgICAgICAgIHRoZW1lX2J3KCkgKyAKICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQoc2l6ZT0xNCksYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dChzaXplPTE0KSwgbGVnZW5kLnBvc2l0aW9uID0gYygwLjgsMC43KSwgbGVnZW5kLnRleHQgPWVsZW1lbnRfdGV4dChzaXplPTE2KSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE0KSkgCgpjb21wYXJlX3Zhcl9kaXN0cmlidXRpb25zPC1yZXByb2Rfc2FtcGxlcyAlPiUgc2VsZWN0KE1Db1ZOdW1iZXIsIG5fdmFyX29yaWdpbmFsLCBuX3Zhcl9yZXByb2R1Y2libGUpICU+JSBwaXZvdF9sb25nZXIoMjozLCBuYW1lc190bz0idmFyaWFudF90eXBlIiwgdmFsdWVzX3RvPSJuIikgCmxhYmVscyA8LSBjKG5fdmFyX29yaWdpbmFsID0gIlZhcmlhbnRzIGluIGZpcnN0IHJlcGxpY2F0ZSIsIG5fdmFyX3JlcHJvZHVjaWJsZSA9ICJSZXByb2R1Y2libGUgdmFyaWFudHMiKQoKZGlzdHJpYnV0aW9uc19yZXA8LWNvbXBhcmVfdmFyX2Rpc3RyaWJ1dGlvbnMgJT4lIGdncGxvdChhZXMoeD1uKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD0xMCkgKyBmYWNldF9ncmlkKHZhcmlhbnRfdHlwZX4uLCBsYWJlbGxlcj1sYWJlbGxlcih2YXJpYW50X3R5cGUgPSBsYWJlbHMpKSArIHhsYWIoIk51bWJlciBvZiBtaW5vciB2YXJpYW50IHNpdGVzIGluIHNhbXBsZSIpICsgeWxhYigiTnVtYmVyIG9mIHNhbXBsZXMiKSArIHRoZW1lX2J3KCkgKyB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTEyKSwgYXhpcy50aXRsZS54PWVsZW1lbnRfdGV4dChzaXplPTE0KSxheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHNpemU9MTQpLCBsZWdlbmQucG9zaXRpb24gPSBjKDAuOCwwLjcpLCBsZWdlbmQudGV4dCA9ZWxlbWVudF90ZXh0KHNpemU9MTYpLCBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTQpKSAKCm1hZl9yZXA8LW1pbm9yc190YWJsZSAlPiUgbXV0YXRlKHJlY292ZXJlZF9taW5vcj1pZl9lbHNlKG1pbm9yLm9yaWdpbmFsPT1taW5vci5yZXNlcSwxLDAsbWlzc2luZz0wKSkgJT4lIGZpbHRlcihyZWNvdmVyZWRfbWlub3I9PTEpICU+JSBnZ3Bsb3QoYWVzKHg9bWlub3JmcmVxLm9yaWdpbmFsLCB5PW1pbm9yZnJlcS5yZXNlcSkpICsgZ2VvbV9wb2ludChhbHBoYT0wLjUpICsgCiAgeGxhYigiTUFGIGluIGZpcnN0IHJlcGxpY2F0ZSIpICsgeWxhYigiTUFGIGluIHNlY29uZCByZXBsaWNhdGUiKSArCiAgdGhlbWVfYncoKSArIAogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTEyKSwgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRpdGxlLng9ZWxlbWVudF90ZXh0KHNpemU9MTQpLGF4aXMudGl0bGUueT1lbGVtZW50X3RleHQoc2l6ZT0xNCksIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44LDAuNyksIGxlZ2VuZC50ZXh0ID1lbGVtZW50X3RleHQoc2l6ZT0xNiksIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xNCkpIAoKbWFmX3IyPC1taW5vcnNfdGFibGUgJT4lIGZpbHRlcihNQ29WTnVtYmVyICVpbiUgc2FtcGxlc18zcmVwKSAlPiUgZmlsdGVyKHJlY292ZXJlZF9taW5vcj09MSkgJT4lIGxlZnRfam9pbih3b3JraW5nX3NhbXBsZXMpICU+JSBncm91cF9ieShNQ29WTnVtYmVyKSAlPiUgc3VtbWFyaXNlKEN0PW1heChDVCksIHIyPXN1bW1hcnkobG0obWlub3JmcmVxLnJlc2Vxfm1pbm9yZnJlcS5vcmlnaW5hbCkpJHIuc3F1YXJlZCkgJT4lIGZpbHRlcihDdDw1MCkgJT4lIGdncGxvdChhZXMoeD1DdCwgeT1yMikpICsgZ2VvbV9wb2ludChhbHBoYT0wLjUpICsgdGhlbWVfYncoKSArCiAgeGxhYigiQ3QgdmFsdWUiKSArIHlsYWIoZXhwcmVzc2lvbihwYXN0ZShSXjIsICIgTUFGIGluIGZpcnN0IGFuZCBzZWNvbmQgcmVwbGljYXRlIikpKSArIAogICAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQoc2l6ZT0xNCksYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dChzaXplPTE0KSwgbGVnZW5kLnBvc2l0aW9uID0gYygwLjgsMC43KSwgbGVnZW5kLnRleHQgPWVsZW1lbnRfdGV4dChzaXplPTE2KSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE0KSkgCgptYWZfY29ycl9leGFtcGxlczwtbWlub3JzX3RhYmxlICU+JSBtdXRhdGUocmVjb3ZlcmVkX21pbm9yPWlmX2Vsc2UobWlub3Iub3JpZ2luYWw9PW1pbm9yLnJlc2VxLDEsMCxtaXNzaW5nPTApKSAlPiUgZmlsdGVyKHJlY292ZXJlZF9taW5vcj09MSkgJT4lIGZpbHRlcihNQ29WTnVtYmVyICVpbiUgc2FtcGxlKHVuaXF1ZShtaW5vcnNfdGFibGUkTUNvVk51bWJlciksIHNpemU9NiwgcmVwbGFjZT1GQUxTRSkpICU+JSBnZ3Bsb3QoYWVzKHg9bWlub3JmcmVxLm9yaWdpbmFsLCB5PW1pbm9yZnJlcS5yZXNlcSkpICsgZ2VvbV9wb2ludChhbHBoYT0wLjUpICsgdGhlbWVfYncoKSArIGZhY2V0X3dyYXAofk1Db1ZOdW1iZXIpICsgICAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTEyLCBhbmdsZT05MCksIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTEyKSwgYXhpcy50aXRsZS54PWVsZW1lbnRfdGV4dChzaXplPTE0KSxheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHNpemU9MTQpKSArIHhsYWIoIk1BRiBpbiBmaXJzdCByZXBsaWNhdGUiKSArIHlsYWIoIk1BRiBpbiBzZWNvbmQgcmVwbGljYXRlIikKCm1hZl9yZXBfYWxsPC1wbG90X2dyaWQobWFmX3JlcCwgcGxvdF9ncmlkKG1hZl9jb3JyX2V4YW1wbGVzLCBtYWZfcjIsIG5yb3c9MiksIG5jb2w9MikKCmxhYmVscyA8LSBjKGAwYCA9ICJOb24tcmVwcm9kdWNpYmxlIHZhcmlhbnRzIiwgYDFgID0gIlJlcHJvZHVjaWJsZSB2YXJpYW50cyIpCgpzaGFyZWRfcmVwPC1taW5vcnNfdGFibGUgJT4lIGdncGxvdChhZXMoeD1udHBvcykpICsgZ2VvbV9iYXIoY29sb3I9ImJsYWNrIikgKyBmYWNldF9ncmlkKHJlY292ZXJlZF9taW5vcn4uLCBsYWJlbGxlcj1sYWJlbGxlcihyZWNvdmVyZWRfbWlub3IgPSBsYWJlbHMpKSArIHRoZW1lX2J3KCkgKyB4bGFiKCJOdWNsZW90aWRlIHBvc2l0aW9uIikgKyB5bGFiKCJOby4gc2FtcGxlcyB3aXRoIG1pbm9yIHZhcmlhbnQgYXQgcG9zaXRpb24iKSArICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTEyKSwgYXhpcy50aXRsZS54PWVsZW1lbnRfdGV4dChzaXplPTE0KSxheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHNpemU9MTQpLCBsZWdlbmQucG9zaXRpb24gPSBjKDAuOCwwLjcpLCBsZWdlbmQudGV4dCA9ZWxlbWVudF90ZXh0KHNpemU9MTYpLCBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTQpKSArIGFubm90YXRlKCJyZWN0IiwgeG1pbj0yNzg5NCwgeG1heD0yODI5NSwgeW1pbj0wLCB5bWF4PUluZiwgYWxwaGE9MC4xKSArIGFubm90YXRlKCJyZWN0IiwgeG1pbj0yODI3NCwgeG1heD0yOTUzMywgeW1pbj0wLCB5bWF4PUluZiwgYWxwaGE9MC4xKQoKcmVwcm9kdWNpYmxlX211dGF0aW9ucyA8LSBtaW5vcnNfdGFibGUgJT4lIGZpbHRlcihyZWNvdmVyZWRfbWlub3I9PTEpICU+JSBzZWxlY3QoTUNvVk51bWJlcixudHBvcywgbWFqb3I9bWFqb3Iub3JpZ2luYWwsbWlub3I9bWlub3Iub3JpZ2luYWwpCm5vbl9yZXByb2R1Y2libGVfbXV0YXRpb25zIDwtIG1pbm9yc190YWJsZSAlPiUgZmlsdGVyKHJlY292ZXJlZF9taW5vcj09MCkgJT4lIHNlbGVjdChNQ29WTnVtYmVyLG50cG9zLCBtYWpvcj1tYWpvci5vcmlnaW5hbCxtaW5vcj1taW5vci5vcmlnaW5hbCkKCmdlbmVzX3JlcDwtcmVwcm9kdWNpYmxlX211dGF0aW9ucyAlPiUgbGVmdF9qb2luKGdlbmVzKSAlPiUgZ3JvdXBfYnkoZ2VuZV9pZCkgJT4lIHN1bW1hcmlzZShuPW4oKSkgJT4lIGZpbHRlcihnZW5lX2lkIT0iIikgJT4lIGxlZnRfam9pbihnZW5lX2xlbmd0aHMpICU+JSBtdXRhdGUoZGVuc2l0eT1uL2dlbmVfbGVuZ3RoKSAlPiUgZ2dwbG90KGFlcyh4PWdlbmVfaWQsIHk9ZGVuc2l0eSkpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBmaWxsPSJ3aGl0ZSIsIGNvbG9yPSJibGFjayIpICsgdGhlbWVfYncoKSArICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0xMiwgYW5nbGU9OTApLCBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQoc2l6ZT0xNCksYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dChzaXplPTE0KSwgbGVnZW5kLnBvc2l0aW9uID0gYygwLjgsMC43KSwgbGVnZW5kLnRleHQgPWVsZW1lbnRfdGV4dChzaXplPTE2KSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE0KSkgKyB4bGFiKCJHZW5lIikgKyB5bGFiKCJEZW5zaXR5IG9mIHJlcHJvZHVjaWJsZSBtaW5vciB2YXJpYW50cyIpCgpwbG90X2dyaWQocGxvdF9ncmlkKHBsb3RfZ3JpZChkZXB0aHNfcmVwLCBkaXN0cmlidXRpb25zX3JlcCwgbnJvdz0yLCBsYWJlbHM9YygiQSIsIkIiKSksIHBsb3RfZ3JpZChzaGFyZWRfcmVwLCBnZW5lc19yZXAsIG5yb3c9MiwgcmVsX2hlaWdodHM9YygyLDEpKSxuY29sPTIsIGxhYmVscz1jKE5BLCJDIikpLCBtYWZfcmVwX2FsbCwgbmNvbD0yLCBsYWJlbHM9YyhOQSwiRCIpKQoKYTwtcGxvdF9ncmlkKGRlcHRoc19yZXAsIHNoYXJlZF9yZXAsIGRpc3RyaWJ1dGlvbnNfcmVwLCBnZW5lc19yZXAsIG5yb3c9MiwgbGFiZWxzPWMoImEiLCJjIiwiYiIsImQiKSkKYjwtcGxvdF9ncmlkKG1hZl9yZXAsIG1hZl9jb3JyX2V4YW1wbGVzLCBtYWZfcjIsIG5yb3c9MywgbGFiZWxzPWMoImUiLCJmIiwiZyIpKQoKI0ZJR1VSRSBTMgpwbG90X2dyaWQoYSwgYiwgbmNvbD0yLCByZWxfd2lkdGhzPWMoMS41LDEpKQpgYGAKIyBDbGluaWNhbCBjb3JyZWxhdGVzIG9mIG1pbm9yIHZhcmlhbnQgcmljaG5lc3MKCmBgYHtyfQojc2FtcGxlcyBmb3Igd2hpY2ggd2UgaGF2ZSBwYXRpZW50IGluZm8KcGRzPC1yZWFkLmNzdigiTUNvVl9wYXRpZW50X2luZm9ybWF0aW9uLmNzdiIpICU+JSBtdXRhdGUoY2hyb25pY19sdW5nX2Rpc2Vhc2U9YXMuZmFjdG9yKGNocm9uaWNfbHVuZ19kaXNlYXNlKSwgY2hyb25pY19saXZlcl9kaXNlYXNlPWFzLmZhY3RvcihjaHJvbmljX2xpdmVyX2Rpc2Vhc2UpLCBjaHJvbmljX2tpZG5leV9kaXNlYXNlPWFzLmZhY3RvcihjaHJvbmljX2tpZG5leV9kaXNlYXNlKSwgY2hyb25pY19oZWFydF9kaXNlYXNlPWFzLmZhY3RvcihjaHJvbmljX2hlYXJ0X2Rpc2Vhc2UpLCBoeXBlcnRlbnNpb249YXMuZmFjdG9yKGh5cGVydGVuc2lvbiksIGRpYWJldGVzPWFzLmZhY3RvcihkaWFiZXRlcyksIGhpdj1hcy5mYWN0b3IoaGl2KSwgY2FuY2VyPWFzLmZhY3RvcihjYW5jZXIpLCBvYmVzaXR5PWFzLmZhY3RvcihvYmVzaXR5KSwgdHJhbnNwbGFudD1hcy5mYWN0b3IodHJhbnNwbGFudCksIHBsYXNtYT1hcy5mYWN0b3IocGxhc21hKSwgbUFiPWFzLmZhY3RvcihtQWIpLCBhZG1pdHRlZF9ob3NwaXRhbD1hcy5mYWN0b3IoYWRtaXR0ZWRfaG9zcGl0YWwpKQojZmlsdGVyIG91dCBydW4gMTMgYmVjYXVzZSBvZiBzdXNwZWN0ZWQgaGlnaCBjb250YW1pbmF0aW9uCnBkczwtcGRzICU+JSBsZWZ0X2pvaW4od29ya2luZ19zYW1wbGVzKSAlPiUgZmlsdGVyKHJ1bl9pZF9maW5hbCE9IlJ1bl8xMyIpIAojbG93IGN0IHNhbXBsZXMgb25seQpwPC1wZHMgJT4lIGxlZnRfam9pbihzYW1wbGVzX25fdmFyKSAlPiUgZmlsdGVyKENUPD0yNCkKc3VtbWFyeShwJG5fdmFyKQpgYGAKCmBgYHtyfQojUmFuZG9tIEZvcmVzdCBtb2RlbCBmb3IgY2xhc3NpZnlpbmcgbG93LUNUIHNhbXBsZXMgYXMgaGF2aW5nIGhpZ2ggb3IgbG93IG1pbm9yIHZhcmlhbnQgcmljaG5lc3MKcCA8LSBwICU+JSBtdXRhdGUodmFyX2xldmVsPWlmX2Vsc2Uobl92YXI8PTIsICJsb3ciLCJoaWdoIikpICU+JSBtdXRhdGUodmFyX2xldmVsPWFzLmZhY3Rvcih2YXJfbGV2ZWwpKSAlPiUgbXV0YXRlKGNocm9uaWNfaWxsbmVzcz1pZl9lbHNlKGNocm9uaWNfbHVuZ19kaXNlYXNlPT0xIHwgY2hyb25pY19oZWFydF9kaXNlYXNlPT0xIHwgY2hyb25pY19raWRuZXlfZGlzZWFzZT09MSB8IGNocm9uaWNfbGl2ZXJfZGlzZWFzZT09MSB8IGRpYWJldGVzPT0xLDEsMCkpCgpwX3NlbGVjdCA8LSBwICAlPiUgc2VsZWN0KGFnZV9ncm91cCwgc2V4LCBldGhuaWNpdHksIGNocm9uaWNfbHVuZ19kaXNlYXNlLCBjaHJvbmljX2xpdmVyX2Rpc2Vhc2UsIGNocm9uaWNfa2lkbmV5X2Rpc2Vhc2UsIGNocm9uaWNfaGVhcnRfZGlzZWFzZSwgaHlwZXJ0ZW5zaW9uLCBkaWFiZXRlcywgaGl2LCBjYW5jZXIsIG9iZXNpdHksIHRyYW5zcGxhbnQsIHBsYXNtYSwgbUFiLCBhZG1pdHRlZF9ob3NwaXRhbCwgdmFjY2luZV9zdGF0dXNfZ3JvdXAsIHZhcl9sZXZlbCkgCgpwLnJmPC1yYW5kb21Gb3Jlc3QodmFyX2xldmVsfi4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhPXBfc2VsZWN0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG50cmVlPTEwMDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXRyeT01LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW1wb3J0YW5jZSA9IFQpIAoKaW1wb3J0YW5jZS5yYW5kb21Gb3Jlc3QgPC0gYXMuZGF0YS5mcmFtZShyYW5kb21Gb3Jlc3Q6OmltcG9ydGFuY2UocC5yZikpCgppbXBvcnRhbmNlLnJhbmRvbUZvcmVzdDwtaW1wb3J0YW5jZS5yYW5kb21Gb3Jlc3QgJT4lIGFycmFuZ2UoZGVzYyhNZWFuRGVjcmVhc2VBY2N1cmFjeSkpCmltcG9ydGFuY2UucmFuZG9tRm9yZXN0CgpyZi5yb2M8LXJvYyhwX3NlbGVjdCR2YXJfbGV2ZWwscC5yZiR2b3Rlc1ssMl0sIGxldmVscz1jKGNhc2U9ImhpZ2giLGNvbnRyb2w9ImxvdyIpKQphdWMocmYucm9jKQpgYGAKCmBgYHtyfQojUkYgbW9kZWwgcGVyZm9ybWFuY2UgaXMgcG9vciBvdmVyYWxsLCBidXQgaG9zcGl0YWwgYWRtaXNzaW9uIGlzIG1vc3QgaW1wb3J0YW50IGZhY3RvciAtIGFyZSBoaWdoLXZhcmlhbnQgc2FtcGxlcyBvdmVycmVwcmVzZW50ZWQgYW1vbmcgcGF0aWVudHMgcmVxdWlyaW5nIGhvc3BpdGFsaXphdGlvbj8KdGFibGUocCRhZG1pdHRlZF9ob3NwaXRhbCwgcCR2YXJfbGV2ZWwpCmNoaXNxLnRlc3QodGFibGUocCRhZG1pdHRlZF9ob3NwaXRhbCwgcCR2YXJfbGV2ZWwpKQpgYGAKCmBgYHtyfQojd2hpY2ggcGF0aWVudCBmYWN0b3JzIGFyZSBhc3NvY2lhdGVkIHdpdGggaG9zcGl0YWxpemF0aW9uPwpnbG0oYWRtaXR0ZWRfaG9zcGl0YWwgfiBjaHJvbmljX2hlYXJ0X2Rpc2Vhc2UgKyBjaHJvbmljX2x1bmdfZGlzZWFzZSArIGNocm9uaWNfbGl2ZXJfZGlzZWFzZSArIGNocm9uaWNfa2lkbmV5X2Rpc2Vhc2UgKyBjYW5jZXIgKyB0cmFuc3BsYW50ICsgaGl2ICsgaHlwZXJ0ZW5zaW9uICsgZGlhYmV0ZXMgKyBvYmVzaXR5ICsgYWdlX2dyb3VwICsgc2V4LCBkYXRhPXBkcywgZmFtaWx5PSJiaW5vbWlhbCIpICU+JSBzdW1tYXJ5KCkKI2luZGl2aWR1YWwgY29tb3JiaWRpdGllcyB3aWxsIGJlIGRpZmZpY3VsdCB0byBkaXNlbnRhbmdsZSBmcm9tIGhvc3BpdGFsaXphdGlvbiAtIGNvbnRpbnVlIHRvIHRyZWF0IGhvc3BpdGFsaXphdGlvbiBhcyBicm9hZCBpbmRpY2F0b3IKYGBgCgpgYGB7cn0KI2RvZXMgaG9zcGl0YWxpemF0aW9uIGVmZmVjdCBzdGlsbCBleGlzdCB0YWtpbmcgaW50byBhY2NvdW50IENUIHZhbHVlIGFuZCBzZXF1ZW5jaW5nIHJ1bj8KbG1lKGxvZyhuX3ZhcisxKSB+IENUKmFkbWl0dGVkX2hvc3BpdGFsLCByYW5kb209fjF8cnVuX2lkX2ZpbmFsLAogICAgICAgICAgICBkYXRhPXApICU+JSBhbm92YSgpIApgYGAKCmBgYHtyfQojZXhwYW5kaW5nIHRvIGluY2x1ZGUgQ1QgdmFsdWVzID4yNApwZHMgJT4lIGxlZnRfam9pbihzYW1wbGVzX25fdmFyKSAlPiUgZmlsdGVyKCFpcy5uYShDVCkpICU+JSBsbWUoZGF0YT0uLCBsb2cxMChuX3ZhciArIDEpfkNUKmFkbWl0dGVkX2hvc3BpdGFsLCByYW5kb209fjF8cnVuX2lkX2ZpbmFsKSAlPiUgYW5vdmEoKQpgYGAKCgpgYGB7cn0KI0ZJR1VSRSAzQQpob3NwaXRhbF9jdF9hbGw8LXBkcyAlPiUgbGVmdF9qb2luKHNhbXBsZXNfbl92YXIpICU+JSBmaWx0ZXIoIWlzLm5hKENUKSkgJT4lIGdncGxvdChhZXMoeD1DVCwgeT1sb2cobl92YXIrMSksIGZpbGw9YWRtaXR0ZWRfaG9zcGl0YWwpKSArIGdlb21fcG9pbnQoc2hhcGU9MjEsIGFscGhhPTAuNSkrc3RhdF9zbW9vdGgobWV0aG9kPWxtLCBhZXMoY29sb3I9YWRtaXR0ZWRfaG9zcGl0YWwpKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygibGlnaHRncmF5IiwiI0I0MEYyMCIpLCBsYWJlbHM9YygiTm90IGhvc3BpdGFsaXplZCIsIkhvc3BpdGFsaXplZCIpKSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiZGFya2dyYXkiLCIjQjQwRjIwIiksbGFiZWxzPWMoIk5vdCBob3NwaXRhbGl6ZWQiLCJIb3NwaXRhbGl6ZWQiKSkgKyB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTEyKSwgYXhpcy50aXRsZS54PWVsZW1lbnRfdGV4dChzaXplPTE0KSxheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHNpemU9MTQpLCBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xNiksIGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIiwgbGVnZW5kLmRpcmVjdGlvbj0idmVydGljYWwiLCBsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpKSArIHhsYWIoIkNUIHZhbHVlIikgKyB5bGFiKCJMb2cxMChOby4gbWlub3IgdmFyaWFudHMgKyAxKSIpIAoKaG9zcGl0YWxfY3RfYWxsCmBgYAoKYGBge3J9CiNoZWFsdGhjYXJlIHdvcmtlciBzdXJ2ZWlsbGFuY2Ugc2FtcGxlcyAtLSBsb29rIGF0IHN1cnZlaWxsYW5jZSBzYW1wbGVzIGZyb20gcHJlc3VtZWQgcHJlc3ltcHRvbWF0aWMvYXN5bXB0b21hdGljL21pbGRseSBzeW1wdG9tYXRpYyBIQ1dzIGNvbXBhcmVkIHRvIGdlbmVyYWwgcG9wdWxhdGlvbiBvZiBwYXRpZW50cyB3aG8gYXJlIHN5bXB0b21hdGljIGJ1dCBub3QgaG9zcGl0YWxpemVkCnN1cnZfY29tcDwtcGRzICU+JSBsZWZ0X2pvaW4oc2FtcGxlc19uX3ZhcikgJT4lIGZpbHRlcighaXMubmEoQ1QpKSAlPiUgZmlsdGVyKCFpcy5uYShzdXJ2ZWlsbGFuY2Vfc2FtcGxlKSkgJT4lIGZpbHRlcihhZG1pdHRlZF9ob3NwaXRhbD09MCkgJT4lIGZpbHRlcighKHN1cnZlaWxsYW5jZV9zYW1wbGU9PSJZZXMgU3VydmVpbGxhbmNlIiAmIHB1aT09IlBVSSIpKQoKI0ZJR1VSRSAzQgpzdXJ2ZWlsbGFuY2VfY3Q8LSBzdXJ2X2NvbXAgJT4lIGdncGxvdChhZXMoeD1DVCwgeT1sb2cobl92YXIrMSksIGZpbGw9c3VydmVpbGxhbmNlX3NhbXBsZSkpICsgZ2VvbV9wb2ludChzaGFwZT0yMSwgYWxwaGE9MC41KStzdGF0X3Ntb290aChtZXRob2Q9bG0sIGFlcyhjb2xvcj1zdXJ2ZWlsbGFuY2Vfc2FtcGxlKSkgKyB0aGVtZV9idygpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImxpZ2h0Z3JheSIsIiNFNTg2MDEiKSwgbGFiZWxzPWMoIk5vdCBzdXJ2ZWlsbGFuY2UiLCAiSENXIHN1cnZlaWxsYW5jZSIpKSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiZGFya2dyYXkiLCIjRTU4NjAxIiksIGxhYmVscz1jKCJOb3Qgc3VydmVpbGxhbmNlIiwgIkhDVyBzdXJ2ZWlsbGFuY2UiKSkgKyB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTEyKSwgYXhpcy50aXRsZS54PWVsZW1lbnRfdGV4dChzaXplPTE0KSxheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLCBsZWdlbmQudGV4dCA9ZWxlbWVudF90ZXh0KHNpemU9MTYpLCAgbGVnZW5kLnBvc2l0aW9uPSJib3R0b20iLCBsZWdlbmQuZGlyZWN0aW9uPSJ2ZXJ0aWNhbCIsIGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCkpICsgeGxhYigiQ1QgdmFsdWUiKSArIHlsYWIoIkxvZzEwKE1pbm9yIHZhcmlhbnRzIGluIHNhbXBsZSArIDEpIikgCmBgYAoKYGBge3J9CmxtZShkYXRhPXN1cnZfY29tcCwgbG9nMTAobl92YXIgKyAxKX5DVCpzdXJ2ZWlsbGFuY2Vfc2FtcGxlLCByYW5kb209fjF8cnVuX2lkX2ZpbmFsKSAlPiUgYW5vdmEoKQpgYGAKCmBgYHtyfQojZWZmZWN0IG9mIHZhY2NpbmF0aW9uIChwcmVzdW1lZCBsZXNzIHNldmVyZSBkaXNlYXNlKSBjb21wYXJlZCB0byBub24tdmFjY2luYXRpb24gcGF0aWVudHMuIExpbWl0ZWQgdG8gSnVuZSBhbmQgSnVseSwgbm9uLWhvc3BpdGFsaXplZCBvbmx5CnZheF9jb21wPC1wZHMgJT4lIGxlZnRfam9pbihzYW1wbGVzX25fdmFyKSAlPiUgZmlsdGVyKGNvbGxlY3Rpb25fbW9udGggJWluJSBjKCIyMDIxLTA2IiwiMjAyMS0wNyIpKSAlPiUgZmlsdGVyKGFkbWl0dGVkX2hvc3BpdGFsPT0wKSAlPiUgZmlsdGVyKCFpcy5uYSh2YWNjaW5lX3N0YXR1c19ncm91cCkpICU+JSBmaWx0ZXIoIWlzLm5hKENUKSkKCiNGSUdVUkUgM0MKdmF4X2N0PC1wZHMgJT4lIGZpbHRlcihDVDw9NDApICU+JSBsZWZ0X2pvaW4oc2FtcGxlc19uX3ZhcikgJT4lIGZpbHRlcihjb2xsZWN0aW9uX21vbnRoICVpbiUgYygiMjAyMS0wNiIsIjIwMjEtMDciKSkgJT4lIGZpbHRlcihhZG1pdHRlZF9ob3NwaXRhbD09MCkgJT4lIGdncGxvdChhZXMoeD1DVCwgeT1sb2cxMChuX3ZhcisxKSwgZmlsbD12YWNjaW5lX3N0YXR1c19ncm91cCkpICsgZ2VvbV9wb2ludChzaGFwZT0yMSwgYWxwaGE9MC41KStzdGF0X3Ntb290aChtZXRob2Q9bG0sIGFlcyhjb2xvcj12YWNjaW5lX3N0YXR1c19ncm91cCkpICsgdGhlbWVfYncoKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJsaWdodGdyYXkiLCIjNDZBQ0M4IiksIGxhYmVscz1jKCJOb3QgZnVsbHkgdmFjY2luYXRlZCIsICJZZXMgZnVsbHkgdmFjY2luYXRlZCIpKSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiZGFya2dyYXkiLCIjNDZBQ0M4IiksIGxhYmVscz1jKCJOb3QgZnVsbHkgdmFjY2luYXRlZCIsICJZZXMgZnVsbHkgdmFjY2luYXRlZCIpKSArIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTEyKSwgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRpdGxlLng9ZWxlbWVudF90ZXh0KHNpemU9MTQpLGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBsZWdlbmQuZGlyZWN0aW9uID0gInZlcnRpY2FsIiwgbGVnZW5kLnRleHQgPWVsZW1lbnRfdGV4dChzaXplPTE2KSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSkgKyB4bGFiKCJDVCB2YWx1ZSIpICMrIHlsYWIoIkxvZzEwKE1pbm9yIHZhcmlhbnRzIGluIHNhbXBsZSArIDEpIikgKyBsYWJzKGNvbG9yPU5VTEwsIGZpbGw9TlVMTCkKYGBgCgpgYGB7cn0KbG1lKGRhdGE9dmF4X2NvbXAsIGxvZzEwKG5fdmFyICsgMSl+Q1QqdmFjY2luZV9zdGF0dXNfZ3JvdXAsIHJhbmRvbT1+MXxydW5faWRfZmluYWwpICU+JSBhbm92YSgpCmBgYAoKYGBge3J9CiNGSUdVUkUgMzogbWlub3IgdmFyaWFudCByaWNobmVzcyBpbiBwYXRpZW50cyByZXF1aXJpbmcgaG9zcGl0YWxpemF0aW9uOyBhc3ltcHRvbWF0aWMgaGVhbHRoY2FyZSB3b3JrZXJzOyB2YWNjaW5hdGVkIHBhdGllbnRzCnBsb3RfZ3JpZChob3NwaXRhbF9jdF9hbGwsIHN1cnZlaWxsYW5jZV9jdCwgdmF4X2N0LCBuY29sPTMsIGFsaWduPSJodiIsIGxhYmVscz0iYXV0byIpCmBgYAoKYGBge3J9CiNGaWd1cmUgUzM6IG1pbm9yIHZhcmlhbnQgcmljaG5lc3MgaW4gcGF0aWVudHMgcmVxdWlyaW5nIGhvc3BpdGFsaXphdGlvbjsgYXN5bXB0b21hdGljIGhlYWx0aGNhcmUgd29ya2VyczsgdmFjY2luYXRlZCBwYXRpZW50cywgc2VwYXJhdGVkIGJ5IGxvdy9oaWdoIENUIHNhbXBsZXMKaG9zcF9jdF9sb3c8LXBkcyAlPiUgbGVmdF9qb2luKHNhbXBsZXNfbl92YXIpICU+JSBmaWx0ZXIoIWlzLm5hKENUKSkgJT4lIGZpbHRlcihDVDw9MjQpICU+JSBnZ3Bsb3QoYWVzKHg9Q1QsIHk9bG9nKG5fdmFyKzEpLCBmaWxsPWFkbWl0dGVkX2hvc3BpdGFsKSkgKyBnZW9tX3BvaW50KHNoYXBlPTIxLCBhbHBoYT0wLjUpK3N0YXRfc21vb3RoKG1ldGhvZD1sbSwgYWVzKGNvbG9yPWFkbWl0dGVkX2hvc3BpdGFsKSkgKyB0aGVtZV9idygpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImxpZ2h0Z3JheSIsIiNCNDBGMjAiKSwgbGFiZWxzPWMoIk5vdCBob3NwaXRhbGl6ZWQiLCJIb3NwaXRhbGl6ZWQiKSkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImRhcmtncmF5IiwiI0I0MEYyMCIpLGxhYmVscz1jKCJOb3QgaG9zcGl0YWxpemVkIiwiSG9zcGl0YWxpemVkIikpICsgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQoc2l6ZT0xNCksYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dChzaXplPTE0KSwgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTYpLCBsZWdlbmQucG9zaXRpb249ImJvdHRvbSIsIGxlZ2VuZC5kaXJlY3Rpb249InZlcnRpY2FsIiwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSkgKyB4bGFiKCJDVCB2YWx1ZSIpICsgeWxhYigiTG9nMTAoTm8uIG1pbm9yIHZhcmlhbnRzICsgMSkiKSAKCmhvc3BfY3RfaGlnaDwtcGRzICU+JSBsZWZ0X2pvaW4oc2FtcGxlc19uX3ZhcikgJT4lIGZpbHRlcighaXMubmEoQ1QpKSAlPiUgZmlsdGVyKENUPjI0KSU+JSBnZ3Bsb3QoYWVzKHg9Q1QsIHk9bG9nKG5fdmFyKzEpLCBmaWxsPWFkbWl0dGVkX2hvc3BpdGFsKSkgKyBnZW9tX3BvaW50KHNoYXBlPTIxLCBhbHBoYT0wLjUpK3N0YXRfc21vb3RoKG1ldGhvZD1sbSwgYWVzKGNvbG9yPWFkbWl0dGVkX2hvc3BpdGFsKSkgKyB0aGVtZV9idygpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImxpZ2h0Z3JheSIsIiNCNDBGMjAiKSwgbGFiZWxzPWMoIk5vdCBob3NwaXRhbGl6ZWQiLCJIb3NwaXRhbGl6ZWQiKSkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImRhcmtncmF5IiwiI0I0MEYyMCIpLGxhYmVscz1jKCJOb3QgaG9zcGl0YWxpemVkIiwiSG9zcGl0YWxpemVkIikpICsgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQoc2l6ZT0xNCksYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dChzaXplPTE0KSwgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTYpLCBsZWdlbmQucG9zaXRpb249ImJvdHRvbSIsIGxlZ2VuZC5kaXJlY3Rpb249InZlcnRpY2FsIiwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSkgKyB4bGFiKCJDVCB2YWx1ZSIpICsgeWxhYigiTG9nMTAoTm8uIG1pbm9yIHZhcmlhbnRzICsgMSkiKSAKCmhjd19jdF9sb3c8LSBzdXJ2X2NvbXAgJT4lIGZpbHRlcihDVDw9MjQpICU+JSBnZ3Bsb3QoYWVzKHg9Q1QsIHk9bG9nKG5fdmFyKzEpLCBmaWxsPXN1cnZlaWxsYW5jZV9zYW1wbGUpKSArIGdlb21fcG9pbnQoc2hhcGU9MjEsIGFscGhhPTAuNSkrc3RhdF9zbW9vdGgobWV0aG9kPWxtLCBhZXMoY29sb3I9c3VydmVpbGxhbmNlX3NhbXBsZSkpICsgdGhlbWVfYncoKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJsaWdodGdyYXkiLCIjRTU4NjAxIikpICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJkYXJrZ3JheSIsIiNFNTg2MDEiKSkgKyB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTEyKSwgYXhpcy50aXRsZS54PWVsZW1lbnRfdGV4dChzaXplPTE0KSxheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHNpemU9MTQpLCBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xNiksIGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIiwgbGVnZW5kLmRpcmVjdGlvbj0idmVydGljYWwiLCBsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpKSArIHhsYWIoIkNUIHZhbHVlIikgKyB5bGFiKCJMb2cxMChOby4gbWlub3IgdmFyaWFudHMgKyAxKSIpIAoKaGN3X2N0X2hpZ2g8LXN1cnZfY29tcCAlPiUgZmlsdGVyKENUPjI0KSAlPiUgZ2dwbG90KGFlcyh4PUNULCB5PWxvZyhuX3ZhcisxKSwgZmlsbD1zdXJ2ZWlsbGFuY2Vfc2FtcGxlKSkgKyBnZW9tX3BvaW50KHNoYXBlPTIxLCBhbHBoYT0wLjUpK3N0YXRfc21vb3RoKG1ldGhvZD1sbSwgYWVzKGNvbG9yPXN1cnZlaWxsYW5jZV9zYW1wbGUpKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygibGlnaHRncmF5IiwiI0U1ODYwMSIpKSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiZGFya2dyYXkiLCIjRTU4NjAxIikpICsgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQoc2l6ZT0xNCksYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dChzaXplPTE0KSwgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTYpLCBsZWdlbmQucG9zaXRpb249ImJvdHRvbSIsIGxlZ2VuZC5kaXJlY3Rpb249InZlcnRpY2FsIiwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSkgKyB4bGFiKCJDVCB2YWx1ZSIpICsgeWxhYigiTG9nMTAoTm8uIG1pbm9yIHZhcmlhbnRzICsgMSkiKSAKCnZheF9jdF9sb3c8LXZheF9jb21wICU+JSBmaWx0ZXIoQ1Q8PTI0KSAlPiUgZ2dwbG90KGFlcyh4PUNULCB5PWxvZyhuX3ZhcisxKSwgZmlsbD12YWNjaW5lX3N0YXR1c19ncm91cCkpICsgZ2VvbV9wb2ludChzaGFwZT0yMSwgYWxwaGE9MC41KStzdGF0X3Ntb290aChtZXRob2Q9bG0sIGFlcyhjb2xvcj12YWNjaW5lX3N0YXR1c19ncm91cCkpICsgdGhlbWVfYncoKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJsaWdodGdyYXkiLCIjNDZBQ0M4IikpICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJkYXJrZ3JheSIsIiM0NkFDQzgiKSkgKyB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTEyKSwgYXhpcy50aXRsZS54PWVsZW1lbnRfdGV4dChzaXplPTE0KSxheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHNpemU9MTQpLCBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xNiksIGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIiwgbGVnZW5kLmRpcmVjdGlvbj0idmVydGljYWwiLCBsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpKSArIHhsYWIoIkNUIHZhbHVlIikgKyB5bGFiKCJMb2cxMChOby4gbWlub3IgdmFyaWFudHMgKyAxKSIpIAoKdmF4X2N0X2hpZ2g8LXZheF9jb21wICU+JSBmaWx0ZXIoQ1Q+MjQpICU+JSBnZ3Bsb3QoYWVzKHg9Q1QsIHk9bG9nKG5fdmFyKzEpLCBmaWxsPXZhY2NpbmVfc3RhdHVzX2dyb3VwKSkgKyBnZW9tX3BvaW50KHNoYXBlPTIxLCBhbHBoYT0wLjUpK3N0YXRfc21vb3RoKG1ldGhvZD1sbSwgYWVzKGNvbG9yPXZhY2NpbmVfc3RhdHVzX2dyb3VwKSkgKyB0aGVtZV9idygpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImxpZ2h0Z3JheSIsIiM0NkFDQzgiKSkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImRhcmtncmF5IiwiIzQ2QUNDOCIpKSArIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTEyKSwgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRpdGxlLng9ZWxlbWVudF90ZXh0KHNpemU9MTQpLGF4aXMudGl0bGUueT1lbGVtZW50X3RleHQoc2l6ZT0xNCksIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE2KSwgbGVnZW5kLnBvc2l0aW9uPSJib3R0b20iLCBsZWdlbmQuZGlyZWN0aW9uPSJ2ZXJ0aWNhbCIsIGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCkpICsgeGxhYigiQ1QgdmFsdWUiKSArIHlsYWIoIkxvZzEwKE5vLiBtaW5vciB2YXJpYW50cyArIDEpIikgCgpwbG90X2dyaWQoaG9zcF9jdF9sb3csIGhvc3BfY3RfaGlnaCwgaGN3X2N0X2xvdywgaGN3X2N0X2hpZ2gsIHZheF9jdF9sb3csIHZheF9jdF9oaWdoLCBucm93PTMsIGxhYmVscz0iQVVUTyIpCmBgYAoKCmBgYHtyfQojTEFTU08gcmVncmVzc2lvbiBtb2RlbCB1c2luZyBnbG1uZXQgcGFja2FnZQojaW5jbHVkZSBDVCwgcnVuLCBwYW5nbyBsaW5lYWdlCnBzPC1wZHMgJT4lIGxlZnRfam9pbihzYW1wbGVzX25fdmFyKSAlPiUgZmlsdGVyKCFpcy5uYShDVCkpICU+JSBmaWx0ZXIoIWlzLm5hKHN1cnZlaWxsYW5jZV9zYW1wbGUpKQoKeTwtbG9nMTAocHMkbl92YXIrMSkKeDwtZGF0YS5tYXRyaXgocHNbLCBjKCdhZ2VfZ3JvdXAnLCAnc2V4JywgJ2V0aG5pY2l0eScsICdjaHJvbmljX2x1bmdfZGlzZWFzZScsICdjaHJvbmljX2xpdmVyX2Rpc2Vhc2UnLCAnY2hyb25pY19raWRuZXlfZGlzZWFzZScsICdjaHJvbmljX2hlYXJ0X2Rpc2Vhc2UnLCAnaHlwZXJ0ZW5zaW9uJywgJ2RpYWJldGVzJywgJ2NhbmNlcicsICdvYmVzaXR5JywgJ3RyYW5zcGxhbnQnLCAncGxhc21hJywgJ21BYicsICdhZG1pdHRlZF9ob3NwaXRhbCcsICd2YWNjaW5lX3N0YXR1c19ncm91cCcsICdwYW5nb19saW5lYWdlX2MnLCAnQ1QnLCAncnVuX2lkX2ZpbmFsJywgJ2NvbGxlY3Rpb25fbW9udGgnLCAnc3VydmVpbGxhbmNlX3NhbXBsZScpXSkKCmN2X21vZGVsIDwtIGN2LmdsbW5ldCh4LCB5LCBhbHBoYSA9IDEpCnBsb3QoY3ZfbW9kZWwpIApiZXN0X21vZGVsIDwtIGdsbW5ldCh4LCB5LCBhbHBoYSA9IDEsIGxhbWJkYSA9IGN2X21vZGVsJGxhbWJkYS5taW4pCmJlc3RfbW9kZWwkZGV2LnJhdGlvCmBgYAoKYGBge3J9CiNGSUcgUzQKY29lZihiZXN0X21vZGVsKSAlPiUgYXMubWF0cml4KCkgJT4lIGRhdGEuZnJhbWUoKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCkgJT4lIHJlbmFtZShmYWN0b3I9cm93bmFtZSwgY29lZmZpY2llbnQ9czApICU+JSBmaWx0ZXIoZmFjdG9yIT0iKEludGVyY2VwdCkiKSAlPiUgYXJyYW5nZShkZXNjKGNvZWZmaWNpZW50KSkgJT4lIGdncGxvdChhZXMoeD1jb2VmZmljaWVudCwgeT1mY3RfcmVvcmRlcihmYWN0b3IsY29lZmZpY2llbnQpKSkgKyBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIGZpbGw9IiNFMkQyMDAiLCBjb2xvcj0iYmxhY2siKSArIHRoZW1lX2J3KCkgKyB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTEyKSwgYXhpcy50aXRsZS54PWVsZW1lbnRfdGV4dChzaXplPTE0KSxheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHNpemU9MTQpLCBsZWdlbmQucG9zaXRpb24gPSBjKDAuOCwwLjcpLCBsZWdlbmQudGV4dCA9ZWxlbWVudF90ZXh0KHNpemU9MTYpLCBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTQpKSArIHlsYWIoImZhY3RvciIpCmBgYAojIEV4YW1pbmluZyBoaWdobHkgc2hhcmVkIHNpdGVzCgpgYGB7cn0KCmdlbmVfbGltaXRzPC1nZW5lcyAlPiUgZ3JvdXBfYnkoZ2VuZV9pZCkgJT4lIHN1bW1hcmlzZShzdGFydD1taW4obnRwb3MpLCBlbmQ9bWF4KG50cG9zKSkgJT4lIGZpbHRlcihnZW5lX2lkIT0iIikgJT4lIG11dGF0ZShtb2xlY3VsZT0iIikKZ2VuZV9hcnJvd3M8LWdncGxvdChnZW5lX2xpbWl0cywgYWVzKHhtaW4gPSBzdGFydCwgeG1heCA9IGVuZCwgeT1tb2xlY3VsZSwgbGFiZWwgPSBnZW5lX2lkKSkgKwogIGdlb21fZ2VuZV9hcnJvdyhhcnJvd2hlYWRfaGVpZ2h0ID0gdW5pdCgzLCAibW0iKSwgYXJyb3doZWFkX3dpZHRoID0gdW5pdCgxLCAibW0iKSkgKyBnZW9tX2dlbmVfbGFiZWwoKSArIGdlb21fc2VnbWVudChhZXMoeD0yNjYseT0xLjUseGVuZD0xMzQ2OCx5ZW5kPTEuNSksIHNpemU9MC4yKSArIGFubm90YXRlKCJ0ZXh0IiwgbGFiZWw9Ik9SRjFhIiwgeD01MDAwLCB5PTEuNDEsIHNpemU9MykgKyBnZW9tX3NlZ21lbnQoYWVzKHg9MTM0NjgseT0xLjQseGVuZD0yMTU1NSx5ZW5kPTEuNCksIHNpemU9MC4yKSArIGFubm90YXRlKCJ0ZXh0IiwgbGFiZWw9Ik9SRjFiIiwgeD0xODAwMCwgeT0xLjMxLCBzaXplPTMpICsKICB0aGVtZV9nZW5lcygpICsgeWxhYihOVUxMKSArIHhsYWIoTlVMTCkKCiNIb3cgZG9lcyBkaXZlcnNpdHkgYXQgY29uc2Vuc3VzIGxldmVsIHJlbGF0ZSB0byBkaXZlcnNpdHkgYXQgbWlub3IgbGV2ZWw/CmNvbnNlbnN1c19jaGFuZ2VfbGlzdDwtcmVhZC5jc3YoImFsbF9jb25zZW5zdXNfbWlub3JpdHlfY2hhbmdlcy5jc3YiKSAlPiUgbXV0YXRlKE1Db1ZOdW1iZXI9cmVnbWF0Y2hlcyhuYW1lLCByZWdleHByKCJbTSxSLFMsT11Db1YuWzAtOV0rIiwgbmFtZSkpICU+JSBzdHJfcmVtb3ZlKCItIikgJT4lIHN0cl9yZW1vdmUoIl8iKSkgJT4lIGZpbHRlcihNQ29WTnVtYmVyICVpbiUgd29ya2luZ19zYW1wbGVzJE1Db1ZOdW1iZXIpICU+JSBmaWx0ZXIoIW50cG9zICVpbiUgcHJpbWVyX3Bvc2l0aW9ucykgJT4lIGZpbHRlcihtYWpvciE9cmVmbnQpICU+JSBsZWZ0X2pvaW4od29ya2luZ19zYW1wbGVzKSAjbGlzdCBvZiBjb25zZW5zdXMgY2hhbmdlcwoKY29uc2Vuc3VzX3ZhcmlhbnRzX2J5X250cG9zPC1jb25zZW5zdXNfY2hhbmdlX2xpc3QgJT4lIGdyb3VwX2J5KG50cG9zKSAlPiUgc3VtbWFyaXNlKG5fY29uc2Vuc3VzPW4oKSkgJT4lIGZpbHRlcighbnRwb3MgJWluJSBwcmltZXJfcG9zaXRpb25zKQoKbWlub3JfdmFyaWFudHNfYnlfbnRwb3M8LXJlYWQuY3N2KCJ2YXJpYW50X3NpdGVzX3RocmVzaG9sZC5jc3YiKSAlPiUgZmlsdGVyKE1Db1ZOdW1iZXIgJWluJSB3b3JraW5nX3NhbXBsZXMkTUNvVk51bWJlcikgJT4lIGxlZnRfam9pbih3b3JraW5nX3NhbXBsZXMpICU+JSBncm91cF9ieShudHBvcykgJT4lIHN1bW1hcmlzZShuX21pbm9yPW4oKSkgCgpjb25zZW5zdXNfbWlub3JfYnlfbnRwb3MgPC0gZnVsbF9qb2luKGNvbnNlbnN1c192YXJpYW50c19ieV9udHBvcyxtaW5vcl92YXJpYW50c19ieV9udHBvcykgJT4lIG11dGF0ZShuX2NvbnNlbnN1cz1yZXBsYWNlX25hKG5fY29uc2Vuc3VzLCAwKSwgbl9taW5vcj1yZXBsYWNlX25hKG5fbWlub3IsIDApKSAlPiUgcGl2b3RfbG9uZ2VyKGNvbHM9MjozLCBuYW1lc190bz0idHlwZSIsIHZhbHVlc190bz0ibiIpCgpjb25zZW5zdXNfbWlub3JfYnlfbnRwb3MkdHlwZTwtZmFjdG9yKGNvbnNlbnN1c19taW5vcl9ieV9udHBvcyR0eXBlLCBsZXZlbHM9Yygibl9taW5vciIsIm5fY29uc2Vuc3VzIiksIGxhYmVscz1jKCJNaW5vciB2YXJpYW50IHByZXNlbnQiLCJDb25zZW5zdXMgY2hhbmdlIGZyb20gcmVmZXJlbmNlIikpIAoKc2l0ZXM8LWNvbnNlbnN1c19taW5vcl9ieV9udHBvcyAlPiUgZ2dwbG90KGFlcyh4PW50cG9zLCB5PW4pKSArIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgY29sb3I9ImJsYWNrIikgKyBmYWNldF9ncmlkKHR5cGV+Liwgc2NhbGVzPSJmcmVlIikgKyB0aGVtZV9idygpICsgYW5ub3RhdGUoInJlY3QiLCB4bWluPTI3ODk0LCB4bWF4PTI4Mjk1LCB5bWluPTAsIHltYXg9SW5mLCBhbHBoYT0wLjIsIGZpbGw9IiM4NUQ0RTMiKSArIGFubm90YXRlKCJyZWN0IiwgeG1pbj0yODI3NCwgeG1heD0yOTUzMywgeW1pbj0wLCB5bWF4PUluZiwgYWxwaGE9MC4yLCBmaWxsPSIjRjRCNUJEIikgKyBhbm5vdGF0ZSgicmVjdCIsIHhtaW49MjE1NjMsIHhtYXg9MjUzODQsIHltaW49MCwgeW1heD1JbmYsIGFscGhhPTAuMiwgZmlsbD0iI0ZBRDc3QiIpKyB5bGFiKCJOdW1iZXIgb2Ygc2FtcGxlcyIpICsgeGxhYigiTnVjbGVvdGlkZSBwb3NpdGlvbiIpICsgc2NhbGVfeF9jb250aW51b3VzKG1pbm9yX2JyZWFrcz1zZXEoZnJvbT0wLCB0bz0zMDAwMCwgYnk9NTAwKSkgKyBnZW9tX2hsaW5lKGRhdGEgPSBkYXRhLmZyYW1lKHlpbnQ9bnJvdyh3b3JraW5nX3NhbXBsZXMpKjAuMDIsej0ibl9taW5vciIpLCBhZXMoeWludGVyY2VwdCA9IHlpbnQpLCBsaW5ldHlwZSA9ICJkb3R0ZWQiKQoKI0ZJR1VSRSA0CnNoYXJlZF9zaXRlczwtcGxvdF9ncmlkKGdlbmVfYXJyb3dzLCBzaXRlcywgbnJvdz0yLCBhbGlnbj0iaHYiLCBheGlzPSJidGxyIiwgcmVsX2hlaWdodHM9YygxLDYpKQoKYGBgCgpgYGB7cn0Kd29ya2luZ19zaXRlczwtdmFyaWFudF9zaXRlc190aHJlc2hvbGQgJT4lIGZpbHRlcihNQ29WTnVtYmVyICVpbiUgd29ya2luZ19zYW1wbGVzJE1Db1ZOdW1iZXIpICU+JSBsZWZ0X2pvaW4od29ya2luZ19zYW1wbGVzKSAlPiUgbXV0YXRlKG11dGF0aW9uPXBhc3RlMChtYWpvcixudHBvcyxtaW5vcikpCgpoaWdobHlfc2hhcmVkX3NpdGVzPC13b3JraW5nX3NpdGVzICU+JSBncm91cF9ieShudHBvcykgJT4lIHN1bW1hcmlzZShzYW1wbGVzX2NvbnRhaW5pbmdfbWlub3I9bigpKSAlPiUgYXJyYW5nZShkZXNjKHNhbXBsZXNfY29udGFpbmluZ19taW5vcikpICU+JSBmaWx0ZXIoc2FtcGxlc19jb250YWluaW5nX21pbm9yPm5yb3cod29ya2luZ19zYW1wbGVzKSowLjAyKSAlPiUgcHVsbChudHBvcykKCnNhbXBsZXNfcGVyX3J1bjwtd29ya2luZ19zYW1wbGVzICU+JSBncm91cF9ieShydW5faWRfZmluYWwpICU+JSBzdW1tYXJpc2Uobl9zYW1wbGVzX2luX3J1bj1uKCkpCgp3b3JraW5nX3NpdGVzICU+JSBmaWx0ZXIobnRwb3MgJWluJSBoaWdobHlfc2hhcmVkX3NpdGVzKSAlPiUgcHVsbChNQ29WTnVtYmVyKSAlPiUgdW5pcXVlKCkgLT4gc2FtcGxlc19jb250YWluaW5nX2hzcwoKaHNzX2luZm88LXdvcmtpbmdfc2l0ZXMgJT4lIGZpbHRlcihudHBvcyAlaW4lIGhpZ2hseV9zaGFyZWRfc2l0ZXMpICU+JSBzZWxlY3QobnRwb3MsIG11dGF0aW9uLCBtaW5vcikgJT4lIGZpbHRlcighZHVwbGljYXRlZChtdXRhdGlvbikpICU+JSBsZWZ0X2pvaW4oZ2VuZXMpICU+JSBtdXRhdGUocmV2ZXJzaW9uX3RvX2FuY2VzdHJhbD1pZl9lbHNlKG1pbm9yPT1yZWZudCwieWVzIiwibm8iKSkgJT4lIHNlbGVjdChtdXRhdGlvbiwgZ2VuZV9pZCwgcmV2ZXJzaW9uX3RvX2FuY2VzdHJhbCkKCmhzc19hYTwtcmVhZC5jc3YoImhpZ2hseV9zaGFyZWRfc2l0ZXNfYWEuY3N2IikKaHNzX2FhJGFhPC1mYWN0b3IoaHNzX2FhJGFhLCBsZXZlbHM9YygiT1JGMWE6IFQyODMiLCAiT1JGMWE6IE42MTUiLCAiT1JGMWE6IEsyMDU5IiwgIk9SRjFhOiBNMjYwNiIsICJPUkYxYTogUzI2MjUiLCAiT1JGMWE6IFQzMzA4IiwgIk9SRjFhOiBMMzM1MiIsICJPUkYxYTogRzM4NDYiLCAiT1JGMWI6IFk0NDYiLCAiT1JGMWI6IE4xNjUzIiwgIk9SRjFiOiBMMjI2NyIsICJPUkYxYjogUjI2MTMiLCAiUzogWTE0NCIsICJTOiBRNjc3IiwgIlM6IFA2ODEiLCAiT1JGM2E6IFE1NyIsICJPUkY4OiBIMTciLCAiT1JGODogUzI0IiwgIk46IEQzIiwgIk46IFA2NyIsICJOOiBTMTk0IiwgIk46IFAxOTkiLCAiTjogUjIwMyIsICJOOiBHMjA0IiwgIk46IFQzOTEiKSkKCmhzczwtd29ya2luZ19zaXRlcyAlPiUgZmlsdGVyKG50cG9zICVpbiUgaGlnaGx5X3NoYXJlZF9zaXRlcykgJT4lIGdyb3VwX2J5KG50cG9zLCBtdXRhdGlvbikgJT4lIHN1bW1hcmlzZShuPW4oKSkgJT4lIGxlZnRfam9pbihoc3NfaW5mbykgJT4lIGxlZnRfam9pbihoc3NfYWEpICU+JSBnZ3Bsb3QoYWVzKHg9bXV0YXRpb24sIHk9bikpICsgZmFjZXRfd3JhcChudHBvc35hYSwgc2NhbGVzPSJmcmVlIikgKyBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIGFlcyhmaWxsPXJldmVyc2lvbl90b19hbmNlc3RyYWwpKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJncmF5IiwiYmxhY2siKSkgKyB0aGVtZV9idygpICsgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTkwKSwgbGVnZW5kLnBvc2l0aW9uPWMoMC44NSwwLjA1KSkgKyBsYWJzKGZpbGw9IlJldmVyc2lvbiB0byBhbmNlc3RyYWwgYWxsZWxlIikgKyB5bGFiKCJOby4gc2FtcGxlcyB3aXRoIG1pbm9yIHZhcmlhbnQiKQoKI0ZJR1VSRSBTNQpoc3MKYGBgCgpgYGB7cn0KI2hpZ2hseSBzaGFyZWQgc2l0ZXMgYnkgcnVuCmhpZ2hseV9zaGFyZWRfYnlfcnVuPC13b3JraW5nX3NhbXBsZXMgJT4lIGZpbHRlcihNQ29WTnVtYmVyICVpbiUgc2FtcGxlc19jb250YWluaW5nX2hzcykgJT4lIGdyb3VwX2J5KHJ1bl9pZF9maW5hbCkgJT4lIHN1bW1hcmlzZShjb250YWluaW5nX2hzcz1uKCkpICU+JSBsZWZ0X2pvaW4oc2FtcGxlc19wZXJfcnVuKSAlPiUgcGl2b3RfbG9uZ2VyKGNvbHM9MjozLCBuYW1lc190bz0idHlwZSIsIHZhbHVlc190bz0ibiIpICU+JSBnZ3Bsb3QoYWVzKHg9cnVuX2lkX2ZpbmFsLCB5PW4sIGZpbGw9dHlwZSkpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbj0iZG9kZ2UiLCBjb2xvcj0iYmxhY2siKSArIHRoZW1lX2J3KCkgKyB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9OTApLCBsZWdlbmQucG9zaXRpb249ImJvdHRvbSIsIGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCkpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwid2hpdGUiKSwgbGFiZWxzPWMoIkNvbnRhaW5pbmcgaGlnaGx5IHNoYXJlZCBtaW5vciB2YXJpYW50KHMpIiwiVG90YWwiKSkgKyB4bGFiKCJSdW4gSUQiKSArIHlsYWIoIk5vLiBzYW1wbGVzIikKCiNCLjEuMiBjaGFyYWN0ZXJpc3RpYyBzaXRlcyBieSBydW4KYi4xLjJfc2l0ZXM8LWRhdGEuZnJhbWUobnRwb3M9YygxMDU5LCAxMDMxOSwgMjEzMDQsIDI1NTYzLCAyNzk2NCwgMjg0NzIsIDI4ODY5KSwgYjEyLmFsbGVsZT1jKCJUIiwiVCIsIlQiLCJUIiwiVCIsIlQiLCJUIikpIAoKYjEyX3RhbGxpZXM8LXdvcmtpbmdfc2FtcGxlcyAlPiUgbXV0YXRlKGIxMl9wcmVzZW50PWlmX2Vsc2UocGFuZ29fbGluZWFnZT09IkIuMS4yIiwxLDApKSAlPiUgZ3JvdXBfYnkocnVuX2lkX2ZpbmFsKSAlPiUgc3VtbWFyaXNlKG5fYjEyX2luX3J1bj1zdW0oYjEyX3ByZXNlbnQpKQoKYjEyX3J1bjEzX2lsbHVzdHJhdGlvbjwtd29ya2luZ19zaXRlcyAlPiUgZmlsdGVyKG50cG9zICVpbiUgYi4xLjJfc2l0ZXMkbnRwb3MpICU+JSBsZWZ0X2pvaW4oZ2VuZXMpICU+JSBmaWx0ZXIobWFqb3I9PSJUIiAmIG1pbm9yPT1yZWZudCkgJT4lIGZpbHRlcihwYW5nb19saW5lYWdlPT0iQi4xLjIiKSAlPiUgZ3JvdXBfYnkobnRwb3MsIHJ1bl9pZF9maW5hbCkgJT4lIHN1bW1hcmlzZShuPW4oKSkgJT4lIGxlZnRfam9pbihiMTJfdGFsbGllcykgJT4lIG11dGF0ZShmcmFjdGlvbl9iMTJfd2l0aF9yZXZlcnNpb25fbWlub3I9bi9uX2IxMl9pbl9ydW4pICU+JSBnZ3Bsb3QoYWVzKHg9cnVuX2lkX2ZpbmFsLCB5PWZyYWN0aW9uX2IxMl93aXRoX3JldmVyc2lvbl9taW5vcikpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSArIGZhY2V0X3dyYXAofm50cG9zKSArIHRoZW1lX2J3KCkgKyB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9OTApLCBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpKSArIHlsYWIoIkZyYWN0aW9uIG9mIEIuMS4yIHdpdGggYW5jZXN0cmFsIGFsbGVsZSBpbiBtaW5vcml0eSIpIAoKI1A2ODEgYWxsZWxlcyBieSBydW4KcnVuX2xpc3Q8LWRhdGEuZnJhbWUocnVuX2lkX2ZpbmFsPXVuaXF1ZSh3b3JraW5nX3NhbXBsZXMkcnVuX2lkX2ZpbmFsKSkKCm1ham9yX2J5X3J1bjwtcmVhZC5jc3YoInNpdGVfMjM2MDQuY3N2IikgJT4lIG11dGF0ZShNQ29WTnVtYmVyPXJlZ21hdGNoZXMobmFtZSwgcmVnZXhwcigiTUNvVi5bMC05XSsiLCBuYW1lKSkgJT4lIHN0cl9yZW1vdmUoIi0iKSAlPiUgc3RyX3JlbW92ZSgiXyIpKSAlPiUgZmlsdGVyKE1Db1ZOdW1iZXIgJWluJSBtY292X3NhbXBsZXNfd2l0aF9pbmZvJE1Db1ZOdW1iZXIpICU+JSBsZWZ0X2pvaW4obWNvdl9zYW1wbGVzX3dpdGhfaW5mbykgJT4lIGZpbHRlcihydW5faWRfZmluYWwgJWluJSB3b3JraW5nX3NhbXBsZXMkcnVuX2lkX2ZpbmFsKSAlPiUgZmlsdGVyKG1ham9yICVpbiUgYygiQSIsIkMiLCJUIiwiRyIpKSAlPiUgZ3JvdXBfYnkocnVuX2lkX2ZpbmFsLCBtYWpvcikgJT4lIHN1bW1hcmlzZShuPW4oKSkgJT4lIHJpZ2h0X2pvaW4ocnVuX2xpc3QpIAoKbWlub3JfYnlfcnVuPC1yZWFkLmNzdigic2l0ZV8yMzYwNC5jc3YiKSAlPiUgbXV0YXRlKE1Db1ZOdW1iZXI9cmVnbWF0Y2hlcyhuYW1lLCByZWdleHByKCJNQ29WLlswLTldKyIsIG5hbWUpKSAlPiUgc3RyX3JlbW92ZSgiLSIpICU+JSBzdHJfcmVtb3ZlKCJfIikpICU+JSBmaWx0ZXIoTUNvVk51bWJlciAlaW4lIHdvcmtpbmdfc2FtcGxlcyRNQ29WTnVtYmVyKSAlPiUgbGVmdF9qb2luKHdvcmtpbmdfc2FtcGxlcykgJT4lIGZpbHRlcih0b3RhbGNvdW50Pj0xMDAgJiBtaW5vcmZyZXE+PTAuMDMgJiBtaW5vcmZyZXEgKiB0b3RhbGNvdW50Pj0xMCAmIG1pbm9yICVpbiUgYygiQSIsIlQiLCJHIiwiQyIpKSAlPiUgZ3JvdXBfYnkocnVuX2lkX2ZpbmFsLCBtaW5vcikgJT4lIHN1bW1hcmlzZShuPW4oKSkgJT4lIHJpZ2h0X2pvaW4ocnVuX2xpc3QpCiAgCm1hal9mY3M8LW1ham9yX2J5X3J1biAlPiUgIGdncGxvdChhZXMoeD1ydW5faWRfZmluYWwsIHk9biwgZmlsbD1tYWpvcikpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbj0ic3RhY2siKSArIHRoZW1lX2J3KCkgKyB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9OTApLCBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpKSArIHhsYWIoIlJ1biIpICsgeWxhYigiTm8uIHNhbXBsZXMiKSArIGxhYnMoZmlsbD0iY29uc2Vuc3VzIikKCm1pbl9mY3M8LW1pbm9yX2J5X3J1biAlPiUgIGdncGxvdChhZXMoeD1ydW5faWRfZmluYWwsIHk9biwgZmlsbD1taW5vcikpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbj0ic3RhY2siKSArIHRoZW1lX2J3KCkgKyB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9OTApLCBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpKSArIHhsYWIoIlJ1biIpICsgeWxhYigiTm8uIHNhbXBsZXMiKSArIGxhYnMoZmlsbD0ibWlub3IiKQoKI0ZJR1VSRSBTNgpwbG90X2dyaWQocGxvdF9ncmlkKGIxMl9ydW4xM19pbGx1c3RyYXRpb24sIGhpZ2hseV9zaGFyZWRfYnlfcnVuLCBucm93PTIsIGxhYmVscz1jKCJBIiwiQiIpKSwgcGxvdF9ncmlkKG1hal9mY3MsIG1pbl9mY3MsICBucm93PTIsIGFsaWduPSJodiIpLCBuY29sPTIsIGxhYmVscz1jKE5BLCAiQyIpKQpgYGAKIyBUaW1pbmcgb2YgZGV0ZWN0aW9uIG9mIG1pbm9yIHZhcmlhbnRzIG9mIHBoZW5vdHlwaWNhbGx5IGltcG9ydGFudCBzaXRlcwoKYGBge3J9CnNwaWtlX3NucF90YWJsZTwtcmVhZC5jc3YoInNwaWtlX211dGF0aW9ucy5jc3YiKQpzcGlrZV9zaXRlczwtcmVhZC5jc3YoImFsbF9jb25zZW5zdXNfbWlub3JpdHlfY2hhbmdlcy5jc3YiKSAlPiUgbXV0YXRlKE1Db1ZOdW1iZXI9cmVnbWF0Y2hlcyhuYW1lLCByZWdleHByKCJNQ29WLlswLTldKyIsIG5hbWUpKSAlPiUgc3RyX3JlbW92ZSgiLSIpICU+JSBzdHJfcmVtb3ZlKCJfIikpICU+JSBmaWx0ZXIoTUNvVk51bWJlciAlaW4lIHdvcmtpbmdfc2FtcGxlcyRNQ29WTnVtYmVyKSAlPiUgZmlsdGVyKG50cG9zICVpbiUgc3Bpa2Vfc25wX3RhYmxlJG50cG9zKQoKc2FtcGxlc19zcGlrZV9wcmVzZW5jZV9hYnNlbmNlPC1zcGlrZV9zaXRlcyAlPiUgZmlsdGVyKCFudHBvcyAlaW4lIHByaW1lcl9wb3NpdGlvbnMpICU+JSBsZWZ0X2pvaW4oc3Bpa2Vfc25wX3RhYmxlKSAlPiUgbXV0YXRlKGNvbnNlbnN1c19jaGFuZ2U9aWZfZWxzZShtYWpvcj09YWxsZWxlLDEsMCkpICU+JQogIG11dGF0ZShtaW5vcl9jaGFuZ2U9aWZfZWxzZSh0b3RhbGNvdW50Pj0xMDAgJiBtaW5vcmZyZXE+PTAuMDMgJnRvdGFsY291bnQqbWlub3JmcmVxPj0xMCAmIHRvbG93ZXIoYmlub2NoZWNrKSE9ImZhbHNlIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWlub3I9PWFsbGVsZSwgMSwwKSkgJT4lIHNlbGVjdChtdXRhdGlvbiwgTUNvVk51bWJlciwgY29uc2Vuc3VzX2NoYW5nZSxtaW5vcl9jaGFuZ2UpICU+JSBsZWZ0X2pvaW4od29ya2luZ19zYW1wbGVzKQpgYGAKCgpgYGB7cn0KcGFfdGFsbGllczwtc2FtcGxlc19zcGlrZV9wcmVzZW5jZV9hYnNlbmNlICU+JSBncm91cF9ieShtdXRhdGlvbiwgQ09MTEVDVElPTl9EVCkgJT4lIHN1bW1hcmlzZShuX2NvbnNlbnN1cz1zdW0oY29uc2Vuc3VzX2NoYW5nZSksIG5fbWlub3I9c3VtKG1pbm9yX2NoYW5nZSkpICU+JSBwaXZvdF9sb25nZXIoY29scz0zOjQsIG5hbWVzX3RvPSJ0eXBlIiwgdmFsdWVzX3RvPSJjYXNlcyIpIAoKc3Bpa2VfaW50ZXJlc3Rpbmc8LXBhX3RhbGxpZXMgJT4lIGZpbHRlcihtdXRhdGlvbiAlaW4lIGMoIlMgTlREOiBMMThGIiwgIlMgTlREOiBUMjBOIiwiUyBSQkQ6IE40MzlLIiwiUyBSQkQ6IEw0NTJSIiwiUyBSQkQ6IEU0ODRLIiwgIlMgUkJEOiBFNDg0USIsIlMgUkJEOiBTNDk0UCIsICJTIFJCRDogTjUwMVkiLCAiUyBSQkQ6IEE1MjBTIikpCgpzcGlrZV9pbnRlcmVzdGluZyRtdXRhdGlvbjwtZmFjdG9yKHNwaWtlX2ludGVyZXN0aW5nJG11dGF0aW9uLCBsZXZlbHM9YygiUyBOVEQ6IEwxOEYiLCAiUyBOVEQ6IFQyME4iLCJTIFJCRDogTjQzOUsiLCJTIFJCRDogTDQ1MlIiLCJTIFJCRDogRTQ4NEsiLCAiUyBSQkQ6IEU0ODRRIiwiUyBSQkQ6IFM0OTRQIiwgIlMgUkJEOiBONTAxWSIsICJTIFJCRDogQTUyMFMiKSkKCmhpZ2hfc3Bpa2U8LSBzcGlrZV9pbnRlcmVzdGluZyAlPiUgZmlsdGVyKG11dGF0aW9uICVpbiUgYygiUyBSQkQ6IEw0NTJSIiwiUyBSQkQ6IE41MDFZIikpICU+JSBnZ3Bsb3QoYWVzKHg9Q09MTEVDVElPTl9EVCwgeT1jYXNlcywgY29sb3I9dHlwZSkpICsgZ2VvbV9saW5lKCkgKyBmYWNldF93cmFwKG11dGF0aW9ufi4sIHNjYWxlcz0iZnJlZV95IikgKyBzY2FsZV94X2RhdGUobWlub3JfYnJlYWtzID0gIjEgbW9udGgiKSsgdGhlbWVfYncoKSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiZ3JheSIsIiNGMjFBMDAiKSkgKyB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTEyKSwgYXhpcy50aXRsZS54PWVsZW1lbnRfdGV4dChzaXplPTE0KSxheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHNpemU9MTQpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIGxlZ2VuZC50ZXh0ID1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xNCkpKyB4bGFiKCJDb2xsZWN0aW9uIERhdGUiKSArIHlsYWIoIk5vLiBzYW1wbGVzIikgCgpsb3dlcl9zcGlrZTwtIHNwaWtlX2ludGVyZXN0aW5nICU+JSBmaWx0ZXIoIW11dGF0aW9uICVpbiUgYygiUyBSQkQ6IEw0NTJSIiwiUyBSQkQ6IE41MDFZIikpICU+JSBnZ3Bsb3QoYWVzKHg9Q09MTEVDVElPTl9EVCwgeT1jYXNlcywgY29sb3I9dHlwZSkpICsgZ2VvbV9saW5lKCkgKyBmYWNldF93cmFwKH5tdXRhdGlvbiwgc2NhbGVzPSJmcmVlX3kiKSArIHNjYWxlX3hfZGF0ZShtaW5vcl9icmVha3MgPSAiMSBtb250aCIpK3RoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImdyYXkiLCIjRjIxQTAwIikpICsgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQoc2l6ZT0xNCksYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dChzaXplPTE0KSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBsZWdlbmQudGV4dCA9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTQpKSsgeGxhYigiQ29sbGVjdGlvbiBEYXRlIikgKyB5bGFiKCJOby4gc2FtcGxlcyIpCgpzcGlrZV9wbG90czwtcGxvdF9ncmlkKGhpZ2hfc3Bpa2UsIGxvd2VyX3NwaWtlLCBuY29sPTIpCgpoaWdoX25vbnNwaWtlPC1wYV90YWxsaWVzICU+JSBmaWx0ZXIobXV0YXRpb24gJWluJSBjKCJNOiBJODJUIiwgIk46IEQzNzdZIiwgIk46IFMyMzVGIiwgIk9SRjNhOiBTMjZMIiwgIk9SRjg6IFI1MkkiKSkgJT4lIGdncGxvdChhZXMoeD1DT0xMRUNUSU9OX0RULCB5PWNhc2VzLCBjb2xvcj10eXBlKSkgKyBnZW9tX2xpbmUoKSArIGZhY2V0X3dyYXAofm11dGF0aW9uLHNjYWxlcz0iZnJlZV95IikgKyBzY2FsZV94X2RhdGUobWlub3JfYnJlYWtzID0gIjEgbW9udGgiKSt0aGVtZV9idygpICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJncmF5IiwiI0YyMUEwMCIpLCBsYWJlbHM9YygiQ29uc2Vuc3VzIiwiTWlub3IiKSkgKyAgdGhlbWVfYncoKSArIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTEyKSwgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRpdGxlLng9ZWxlbWVudF90ZXh0KHNpemU9MTQpLGF4aXMudGl0bGUueT1lbGVtZW50X3RleHQoc2l6ZT0xNCksIGxlZ2VuZC5wb3NpdGlvbj1jKDAuOCwwLjIpLCBsZWdlbmQudGV4dCA9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCBsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpKSsgeGxhYigiQ29sbGVjdGlvbiBEYXRlIikgKyB5bGFiKCJOby4gc2FtcGxlcyIpCgpjaHJvbm9sb2dpZXM8LXBsb3RfZ3JpZChzcGlrZV9wbG90cywgaGlnaF9ub25zcGlrZSwgbnJvdz0yLCByZWxfaGVpZ2h0cz1jKDEsMC41KSwgbGFiZWxzPSJhdXRvIikKCgojRklHVVJFIDVBL0IKY2hyb25vbG9naWVzCmBgYAoKYGBge3J9CiMgQi4xLjEuNyBhbmQgQi4xLjYxNy4yIGxpbmVhZ2UtZGVmaW5pbmcgbXV0YXRpb25zIGluIG1pbm9yaXR5CmNhbGN1bGF0ZV90ZXN0PC1mdW5jdGlvbihzYW1wbGVfc2l0ZXNfdGFibGUsIHNucF90YWJsZSwgbWlub3JfbGluZWFnZXNfb2ZfaW50ZXJlc3QsIG1hZl9hdF9zaXRlcywgZGVwdGhfYXRfc2l0ZXMsIG1pbl9yZWFkcywgcHJvcF9zaXRlcywgZnVsbF9zYW1wbGVfbGlzdCkgewojZW1wdHkgZGF0YSBmcmFtZSBvZiBzYW1wbGUgbmFtZSwgbnVjbGVvdGlkZSBwb3NpdGlvbnMgb2YgaW50ZXJlc3QsIGFuZCBtYWpvciBhbmQgbWlub3IgYWxsZWxlcwpzdWJzPC1kYXRhLmZyYW1lKE1Db1ZOdW1iZXI9YXMuY2hhcmFjdGVyKCksIG1pbm9yX2xpbmVhZ2Vfb3JfbXV0YXRpb249YXMuY2hhcmFjdGVyKCksIG50cG9zPWFzLm51bWVyaWMoKSwgbWlub3JmcmVxPWFzLm51bWVyaWMoKSwgdG90YWxjb3VudD1hcy5udW1lcmljKCkpCiNjYWxjdWxhdGUgbnVtYmVyIG9mIG11dGF0aW9ucyBuZWVkZWQgdG8gY291bnQgbWlub3IgbGluZWFnZSBhcyBwcmVzZW50Cm11dGF0aW9uX251bWJlcl90aHJlc2hvbGRzPC1zbnBfdGFibGUgJT4lIGdyb3VwX2J5KGxpbmVhZ2UpICU+JSBzdW1tYXJpc2UodGhyZXNob2xkX21pbm9yX211dGF0aW9ucz1uKCkqcHJvcF9zaXRlcykKI2VtcHR5IGRhdGEgZnJhbWUgb2YgYWxsIHNhbXBsZS9saW5lYWdlIGNvbWJpbmF0aW9ucwpmdWxsX2NvbWJvPC1leHBhbmQuZ3JpZChNQ29WTnVtYmVyPXB1bGwoZnVsbF9zYW1wbGVfbGlzdCwgTUNvVk51bWJlciksIG1pbm9yX2xpbmVhZ2Vfb3JfbXV0YXRpb249bGluZWFnZXNfb2ZfaW50ZXJlc3QpICU+JSBhcnJhbmdlKE1Db1ZOdW1iZXIpCgoja2VlcCBvbmx5IHBvc2l0aW9ucyB3aXRoIG1pbm9yIHZhcmlhbnRzIHByZXNlbnQgYXQgcmlnaHQgTUFGIGFuZCBkZXB0aApkZXB0aF9mcmVxPC1maWx0ZXIoc2FtcGxlX3NpdGVzX3RhYmxlLCBtaW5vcmZyZXE+PW1hZl9hdF9zaXRlcykgJT4lIGZpbHRlcih0b3RhbGNvdW50PmRlcHRoX2F0X3NpdGVzKSAlPiUgZmlsdGVyKG1pbm9yZnJlcSp0b3RhbGNvdW50Pj1taW5fcmVhZHMpCgojY2hlY2sgZm9yIGNvcnJlY3QgYWxsZWxlIGF0IG1pbm9yIHZhcmlhbnQgc2l0ZSBmb3IgZWFjaCBsaW5lYWdlCmZvciAobGluIGluIGxpbmVhZ2VzX29mX2ludGVyZXN0KSB7CiAgcHJpbnQobGluKQogIHNucHM8LWZpbHRlcihzbnBfdGFibGUsIGxpbmVhZ2U9PWxpbikgCiAgdGVtcDwtbGVmdF9qb2luKGRlcHRoX2ZyZXEsIHNucHMsIGJ5PWMoIm50cG9zIj0icG9zaXRpb24iKSkgJT4lIGZpbHRlcighaXMubmEobGluZWFnZSkpICU+JSBmaWx0ZXIobWlub3I9PWFsbGVsZSkgJT4lIHNlbGVjdChNQ29WTnVtYmVyLGxpbmVhZ2UsbnRwb3MsbWlub3JmcmVxLHRvdGFsY291bnQpICU+JSByZW5hbWUoYygibWlub3JfbGluZWFnZV9vcl9tdXRhdGlvbiI9ImxpbmVhZ2UiKSkKICBzdWJzPC1yYmluZChzdWJzLHRlbXApCn0KCndyaXRlLmNzdihzdWJzLCAibWlub3Jfc3Vic190ZW1wX3dvcmtpbmdsaXN0LmNzdiIsIHJvdy5uYW1lcz1GQUxTRSkKcHJpbnQoIk1pbm9yIHZhcmlhbnQgZGVwdGgvZnJlcSB3cml0dGVuIHRvIG1pbm9yX3N1YnNfdGVtcC5jc3YiKQoKI2NvdW50IG51bWJlciBvZiBtdXRhdGlvbnMgb2YgZWFjaCB2YXJpYW50IHByZXNlbnQgCm1pbm9yX3NpdGVzX3RhbGxpZXM8LXN1YnMgJT4lIGdyb3VwX2J5KE1Db1ZOdW1iZXIsbWlub3JfbGluZWFnZV9vcl9tdXRhdGlvbikgJT4lIHN1bW1hcmlzZShudW1iZXJfbWlub3JfbXV0YXRpb25zPW4oKSkgJT4lIGxlZnRfam9pbihtdXRhdGlvbl9udW1iZXJfdGhyZXNob2xkcywgYnk9YygibWlub3JfbGluZWFnZV9vcl9tdXRhdGlvbiI9ImxpbmVhZ2UiKSkgCgojY2FsY3VsYXRlIHdoZXRoZXIgbnVtYmVyIG9mIG11dGF0aW9ucyBpbiB0aGUgc2FtcGxlIGV4Y2VlZHMgdGhyZXNob2xkIGZvciBsaW5lYWdlIGJlaW5nIGNvbnNpZGVyZWQgcHJlc2VudCBpbiB0aGUgbWlub3IgZnJhY3Rpb24KbWlub3Jfc2l0ZXNfdGFsbGllcyAlPiUgZmlsdGVyKG51bWJlcl9taW5vcl9tdXRhdGlvbnM+PXRocmVzaG9sZF9taW5vcl9tdXRhdGlvbnMpICU+JSBzZWxlY3QoTUNvVk51bWJlciwgbWlub3JfbGluZWFnZV9vcl9tdXRhdGlvbikgJT4lIG11dGF0ZShtaW5vcl9wcmVzZW50PTEpICU+JSByaWdodF9qb2luKGZ1bGxfY29tYm8pIC0+IHRhbGxpZXMKCmZpbmFsX3RhbGxpZXM8LWxlZnRfam9pbihmdWxsX2NvbWJvLCB0YWxsaWVzKQpmaW5hbF90YWxsaWVzW2lzLm5hKGZpbmFsX3RhbGxpZXMpXTwtMApwcmludCgiTGlzdCBmaW5hbGl6ZWQiKQpyZXR1cm4oZmluYWxfdGFsbGllcykKfQoKc25wX3RhYmxlPC1yZWFkLmNzdigibGluZWFnZV9hbmRfc2luZ2xlX211dGF0aW9ucy5jc3YiKSAlPiUgbXV0YXRlKHBvc2l0aW9uPWFzLm51bWVyaWMocG9zaXRpb24pKQpsaW5lYWdlc19vZl9pbnRlcmVzdDwtYygiQi4xLjEuNyIsICJCLjEuNjE3LjIiKQoKbmV3X3RhYmxlIDwtY2FsY3VsYXRlX3Rlc3Qoc2FtcGxlX3NpdGVzX3RhYmxlPXZhcmlhbnRfc2l0ZXNfdGhyZXNob2xkLCBzbnBfdGFibGU9c25wX3RhYmxlLCBtaW5vcl9saW5lYWdlc19vZl9pbnRlcmVzdD1saW5lYWdlc19vZl9pbnRlcmVzdCwgbWFmX2F0X3NpdGVzPTAuMDMsIGRlcHRoX2F0X3NpdGVzPTEwMCwgbWluX3JlYWRzPTEwLCBwcm9wX3NpdGVzPTAuNiwgZnVsbF9zYW1wbGVfbGlzdD1zYW1wbGVfbGlzdCkgCgptaW5vcl9saW5lYWdlczwtbmV3X3RhYmxlICU+JSBmaWx0ZXIoTUNvVk51bWJlciAlaW4lIHdvcmtpbmdfc2FtcGxlcyRNQ29WTnVtYmVyKSAlPiUgbGVmdF9qb2luKHdvcmtpbmdfc2FtcGxlcykKCm1pbm9yX2xpbmVhZ2VzICU+JSBmaWx0ZXIobWlub3JfcHJlc2VudD09MSkgJT4lIGFycmFuZ2UoQ09MTEVDVElPTl9EVCkKCmBgYAoKYGBge3J9CiN3ZXJlIHRoZXJlIG90aGVyIEIuMS4xLjcgc2FtcGxlcyBpbiB0aGUgc2FtZSBzZXF1ZW5jaW5nIHJ1bj8KbWlub3JfbGluZWFnZXMgJT4lIGZpbHRlcihtaW5vcl9saW5lYWdlX29yX211dGF0aW9uPT0iQi4xLjEuNyIpICU+JSBmaWx0ZXIobWlub3JfcHJlc2VudD09MSkgJT4lIGdyb3VwX2J5KHJ1bl9pZF9maW5hbCkgJT4lIHN1bW1hcmlzZShuPW4oKSkgJT4lIHB1bGwocnVuX2lkX2ZpbmFsKSAtPiByCm1jb3Zfc2FtcGxlc193aXRoX2luZm8gJT4lIGZpbHRlcihwYW5nb19saW5lYWdlPT0iQi4xLjEuNyIpICU+JSBncm91cF9ieShydW5faWRfZmluYWwpICU+JSBzdW1tYXJpc2Uobj1uKCkpICU+JSBwdWxsKHJ1bl9pZF9maW5hbCkgLT4gcmMKc2V0ZGlmZihyLHJjKSAjcnVuIDMyIGhhcyBubyBjb25zZW5zdXMgQi4xLjcgYnV0IG9uZSBtaW5vciAoZnJvbSBEZWNlbWJlcikKCiN3ZXJlIGFueSBvZiB0aGVzZSBtaW5vci1CLjEuMS43IHNhbXBsZXMgaW4gdGhlIHJlc2VxdWVuY2luZyBkYXRhc2V0PwpzYW1wbGVzX3RvX3JlY2hlY2sgPC1taW5vcl9saW5lYWdlcyAlPiUgZmlsdGVyKG1pbm9yX2xpbmVhZ2Vfb3JfbXV0YXRpb249PSJCLjEuMS43IikgJT4lIGZpbHRlcihtaW5vcl9wcmVzZW50PT0xKSAlPiUgZmlsdGVyKE1Db1ZOdW1iZXIgJWluJSBhbGxfcmVwbGljYXRlc190YWJsZV9maWx0JE1Db1ZOdW1iZXIpICU+JSBwdWxsKE1Db1ZOdW1iZXIpCgptaW5vcnNfdGFibGUgJT4lIGZpbHRlcihNQ29WTnVtYmVyICVpbiUgc2FtcGxlc190b19yZWNoZWNrKSAlPiUgZmlsdGVyKG50cG9zICVpbiUgZmlsdGVyKHNucF90YWJsZSwgbGluZWFnZT09IkIuMS4xLjciKSRwb3NpdGlvbikgJT4lIGxlZnRfam9pbihmaWx0ZXIoc25wX3RhYmxlLCBsaW5lYWdlPT0iQi4xLjEuNyIpLCBieT1jKCJudHBvcyI9InBvc2l0aW9uIikpICU+JSBtdXRhdGUoYjExN19hbGxlbGU9aWZfZWxzZShtaW5vci5vcmlnaW5hbD09YWxsZWxlLDEsMCkpICU+JSBmaWx0ZXIoYjExN19hbGxlbGU9PTEpICU+JSBncm91cF9ieShNQ29WTnVtYmVyKSAlPiUgc3VtbWFyaXNlKG5faW5fb3JpZ2luYWw9bigpLCBuX3JlY292ZXJlZD1zdW0ocmVjb3ZlcmVkX21pbm9yKSkgJT4lIGFycmFuZ2Uobl9yZWNvdmVyZWQpICU+JSBtdXRhdGUobWlub3JfZnJhY3Rpb25fcmVwcm9kdWNlZD1pZl9lbHNlKG5fcmVjb3ZlcmVkPj0xMS40LCAxLDAsIG1pc3Npbmc9TkFfcmVhbF8pKQpgYGAKCmBgYHtyfQpiMTE3X21pbm9yX2RhdGVzPC1taW5vcl9saW5lYWdlcyAlPiUgZmlsdGVyKG1pbm9yX2xpbmVhZ2Vfb3JfbXV0YXRpb249PSJCLjEuMS43IikgJT4lIGZpbHRlcihtaW5vcl9wcmVzZW50PT0xKSAlPiUgIGdncGxvdChhZXMoeD1DT0xMRUNUSU9OX0RUKSkgKyBnZW9tX2Jhcihjb2xvcj0iYmxhY2siKSArIHNjYWxlX3hfZGF0ZShtaW5vcl9icmVha3MgPSAiMSBtb250aCIpICsgdGhlbWVfYncoKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD1hcy5udW1lcmljKGFzLkRhdGUoIjIwMjEtMDEtMTIiKSksIGxpbmV0eXBlPSJkYXNoZWQiLCBjb2xvcj0iZ3JheSIpICsgCiAgYW5ub3RhdGUoZ2VvbSA9ICJ0ZXh0IiwgeCA9YXMuRGF0ZSgiMjAyMS0wMS0xMiIpLCB5PTEuNSwgbGFiZWwgPSAiQWxwaGEgd2F2ZSIsIHZqdXN0PTAsIGFuZ2xlID0gOTApICsKICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PWFzLm51bWVyaWMoYXMuRGF0ZSgiMjAyMS0wNi0xNSIpKSwgbGluZXR5cGU9ImRhc2hlZCIsIGNvbG9yPSJncmF5IikgKyAKICBhbm5vdGF0ZShnZW9tID0gInRleHQiLCB4ID1hcy5EYXRlKCIyMDIxLTA2LTE1IiksIHk9MS41LCBsYWJlbCA9ICJEZWx0YSB3YXZlIiwgdmp1c3Q9MCwgYW5nbGUgPSA5MCkgKyAKICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTEyKSwgYXhpcy50aXRsZS54PWVsZW1lbnRfdGV4dChzaXplPTE0KSxheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHNpemU9MTQpLCBsZWdlbmQucG9zaXRpb24gPSBjKDAuOCwwLjcpLCBsZWdlbmQudGV4dCA9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTQpKSArIHhsYWIoIkNvbGxlY3Rpb24gZGF0ZSIpICsgeWxhYigiTm8uIHNhbXBsZXMiKQoKI0ZJR1VSRSA1CnBsb3RfZ3JpZChjaHJvbm9sb2dpZXMsIGIxMTdfbWlub3JfZGF0ZXMsIG5yb3c9MiwgbGFiZWxzPWMoTkEsImMiKSwgcmVsX2hlaWdodHMgPSBjKDMsMSkpCmBgYAoKYGBge3J9CmluY2x1c2lvbl90YWJsZTwtbWNvdl9zYW1wbGVzX3dpdGhfaW5mbyAlPiUgZmlsdGVyKENPTExFQ1RJT05fRFQ+PSIyMDIwLTEyLTAxIiAmIENPTExFQ1RJT05fRFQ8PSIyMDIxLTA3LTMxIikgJT4lIHNlbGVjdChNQ29WTnVtYmVyKSAlPiUgbXV0YXRlKGhpZ2hfY292ZXJhZ2VfaW5jbHVkZWQ9aWZfZWxzZShNQ29WTnVtYmVyICVpbiUgd29ya2luZ19zYW1wbGVzJE1Db1ZOdW1iZXIsIDEsMCksIGNsaW5pY2FsX2luY2x1ZGVkX2hhc19DVD1pZl9lbHNlKE1Db1ZOdW1iZXIgJWluJSBmaWx0ZXIocGRzLGlzLm5hKENUKSkkTUNvVk51bWJlciwxLDApKSAKCndyaXRlLmNzdihpbmNsdXNpb25fdGFibGUsICJpbmNsdXNpb25fdGFibGUuY3N2IikKYGBgCg==